1 /*
  2  * ilibglobal.js - define the ilib name space
  3  * 
  4  * Copyright © 2012-2014, JEDLSoft
  5  *
  6  * Licensed under the Apache License, Version 2.0 (the "License");
  7  * you may not use this file except in compliance with the License.
  8  * You may obtain a copy of the License at
  9  *
 10  *     http://www.apache.org/licenses/LICENSE-2.0
 11  *
 12  * Unless required by applicable law or agreed to in writing, software
 13  * distributed under the License is distributed on an "AS IS" BASIS,
 14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  *
 16  * See the License for the specific language governing permissions and
 17  * limitations under the License.
 18  */
 19 
 20 /**
 21  * @namespace The global namespace that contains all ilib functions and classes.
 22  */
 23 var ilib = ilib || {};
 24 
 25 /**
 26  * Return the current version of ilib.
 27  * 
 28  * @static
 29  * @return {string} a version string for this instance of ilib
 30  */
 31 ilib.getVersion = function () {
 32     // increment this for each release
 33     return "10.0"
 34     ;
 35 };
 36 
 37 /**
 38  * Place where resources and such are eventually assigned.
 39  */
 40 ilib.data = {
 41     norm: {
 42         nfc: {},
 43         nfd: {},
 44         nfkd: {},
 45         ccc: {}
 46     },
 47     zoneinfo: {
 48         "Etc/UTC":{"o":"0:0","f":"UTC"},
 49         "local":{"f":"local"}
 50     },
 51     /** @type {null|Object.<string,Array.<Array.<number>>>} */ ctype: null,
 52     /** @type {null|Object.<string,Array.<Array.<number>>>} */ ctype_c: null,
 53     /** @type {null|Object.<string,Array.<Array.<number>>>} */ ctype_l: null,
 54     /** @type {null|Object.<string,Array.<Array.<number>>>} */ ctype_m: null,
 55     /** @type {null|Object.<string,Array.<Array.<number>>>} */ ctype_p: null,
 56     /** @type {null|Object.<string,Array.<Array.<number>>>} */ ctype_z: null,
 57     /** @type {null|Object.<string,Array.<Array.<number>>>} */ scriptToRange: null,
 58     /** @type {null|Object.<string,string|Object.<string|Object.<string,string>>>} */ dateformats: null
 59 };
 60 
 61 if (typeof(window) !== 'undefined') {
 62     window["ilib"] = ilib;
 63 }
 64 
 65 // export ilib for use as a module in nodejs
 66 if (typeof(exports) !== 'undefined') {
 67     exports.ilib = ilib;
 68 }
 69 
 70 ilib.pseudoLocales = ["zxx-XX"];
 71 
 72 /**
 73  * Sets the pseudo locale. Pseudolocalization (or pseudo-localization) is used for testing
 74  * internationalization aspects of software. Instead of translating the text of the software
 75  * into a foreign language, as in the process of localization, the textual elements of an application
 76  * are replaced with an altered version of the original language.These specific alterations make
 77  * the original words appear readable, but include the most problematic characteristics of 
 78  * the world's languages: varying length of text or characters, language direction, and so on.
 79  * Regular Latin pseudo locale: eu-ES and RTL pseudo locale: ps-AF
 80  * 
 81  * @param {string|undefined|null} localename the locale specifier for the pseudo locale
 82  */
 83 ilib.setAsPseudoLocale = function (localename) {
 84    if (localename) {
 85 	   ilib.pseudoLocales.push(localename)
 86    }
 87 };
 88 
 89 /**
 90  * Reset the list of pseudo locales back to the default single locale of zxx-XX.
 91  */
 92 ilib.clearPseudoLocales = function() {
 93 	ilib.pseudoLocales = ["zxx-XX"];
 94 };
 95 
 96 /**
 97  * Return the name of the platform
 98  * @private
 99  * @static
100  * @return {string} string naming the platform
101  */
102 ilib._getPlatform = function () {
103     if (!ilib._platform) {
104         if (typeof(environment) !== 'undefined') {
105             ilib._platform = "rhino";
106         } else if (typeof(process) !== 'undefined' || typeof(require) !== 'undefined') {
107             ilib._platform = "nodejs";
108         } else if (typeof(window) !== 'undefined') {
109             ilib._platform = (typeof(PalmSystem) !== 'undefined') ? "webos" : "browser";
110         } else {
111             ilib._platform = "unknown";
112         }
113     }    
114     return ilib._platform;
115 };
116 
117 /**
118  * If this ilib is running in a browser, return the name of that browser.
119  * @private
120  * @static
121  * @return {string|undefined} the name of the browser that this is running in ("firefox", "chrome", "ie", 
122  * "safari", or "opera"), or undefined if this is not running in a browser or if
123  * the browser name could not be determined 
124  */
125 ilib._getBrowser = function () {
126 	var browser = undefined;
127 	if (ilib._getPlatform() === "browser") {
128 		if (navigator && navigator.userAgent) {
129 			if (navigator.userAgent.indexOf("Firefox") > -1) {
130 				browser = "firefox";
131 			}
132 			if (navigator.userAgent.indexOf("Opera") > -1) {
133 				browser = "opera";
134 			}
135 			if (navigator.userAgent.indexOf("Chrome") > -1) {
136 				browser = "chrome";
137 			}
138 			if (navigator.userAgent.indexOf(" .NET") > -1) {
139 				browser = "ie";
140 			}
141 			if (navigator.userAgent.indexOf("Safari") > -1) {
142 				// chrome also has the string Safari in its userAgent, but the chrome case is 
143 				// already taken care of above
144 				browser = "safari";
145 			}
146 		}
147 	}
148 	return browser;
149 };
150 
151 /**
152  * Return true if the global variable is defined on this platform.
153  * @private
154  * @static
155  * @return {boolean} true if the global variable is defined on this platform, false otherwise
156  */
157 ilib._isGlobal = function(name) {
158     switch (ilib._getPlatform()) {
159         case "rhino":
160             var top = (function() {
161               return (typeof global === 'object') ? global : this;
162             })();
163             return typeof(top[name]) !== undefined;
164         case "nodejs":
165             var root = typeof(global) !== 'undefined' ? global : this;
166             return root && typeof(root[name]) !== undefined;
167             
168         default:
169             return typeof(window[name]) !== undefined;
170     }
171 };
172 
173 /**
174  * Sets the default locale for all of ilib. This locale will be used
175  * when no explicit locale is passed to any ilib class. If the default
176  * locale is not set, ilib will attempt to use the locale of the
177  * environment it is running in, if it can find that. If not, it will
178  * default to the locale "en-US". If a type of parameter is string, 
179  * ilib will take only well-formed BCP-47 tag  <p>
180  * 
181  * Depends directive: !depends ilibglobal.js
182  * 
183  * @static
184  * @param {string|undefined|null} spec the locale specifier for the default locale
185  */
186 ilib.setLocale = function (spec) {
187     if (typeof(spec) === 'string' || !spec) {
188         ilib.locale = spec;
189     }
190     // else ignore other data types, as we don't have the dependencies
191     // to look into them to find a locale
192 };
193 
194 /**
195  * Return the default locale for all of ilib if one has been set. This 
196  * locale will be used when no explicit locale is passed to any ilib 
197  * class. If the default
198  * locale is not set, ilib will attempt to use the locale of the
199  * environment it is running in, if it can find that. If not, it will
200  * default to the locale "en-US".<p>
201  * 
202  * Depends directive: !depends ilibglobal.js 
203  * 
204  * @static
205  * @return {string} the locale specifier for the default locale
206  */
207 ilib.getLocale = function () {
208     if (typeof(ilib.locale) !== 'string') {
209         if (typeof(navigator) !== 'undefined' && typeof(navigator.language) !== 'undefined') {
210             // running in a browser
211             ilib.locale = navigator.language.substring(0,3) + navigator.language.substring(3,5).toUpperCase();  // FF/Opera/Chrome/Webkit
212             if (!ilib.locale) {
213                 // IE on Windows
214                 var lang = typeof(navigator.browserLanguage) !== 'undefined' ? 
215                     navigator.browserLanguage : 
216                     (typeof(navigator.userLanguage) !== 'undefined' ? 
217                         navigator.userLanguage : 
218                         (typeof(navigator.systemLanguage) !== 'undefined' ?
219                             navigator.systemLanguage :
220                             undefined));
221                 if (typeof(lang) !== 'undefined' && lang) {
222                     // for some reason, MS uses lower case region tags
223                     ilib.locale = lang.substring(0,3) + lang.substring(3,5).toUpperCase();
224                 }
225             }
226         } else if (typeof(PalmSystem) !== 'undefined' && typeof(PalmSystem.locales) !== 'undefined') {
227             // webOS
228             if (typeof(PalmSystem.locales.UI) != 'undefined' && PalmSystem.locales.UI.length > 0) {
229                 ilib.locale = PalmSystem.locales.UI;
230             }
231         } else if (typeof(environment) !== 'undefined' && typeof(environment.user) !== 'undefined') {
232             // running under rhino
233             if (typeof(environment.user.language) === 'string' && environment.user.language.length > 0) {
234                 ilib.locale = environment.user.language;
235                 if (typeof(environment.user.country) === 'string' && environment.user.country.length > 0) {
236                     ilib.locale += '-' + environment.user.country;
237                 }
238             }
239         } else if (typeof(process) !== 'undefined' && typeof(process.env) !== 'undefined') {
240             // running under nodejs
241             var lang = process.env.LANG || process.env.LC_ALL;
242             // the LANG variable on unix is in the form "lang_REGION.CHARSET"
243             // where language and region are the correct ISO codes separated by
244             // an underscore. This translate it back to the BCP-47 form.
245             if (lang && lang !== 'undefined') {
246                 ilib.locale = lang.substring(0,2).toLowerCase() + '-' + lang.substring(3,5).toUpperCase();
247             }
248         }
249              
250         ilib.locale = typeof(ilib.locale) === 'string' ? ilib.locale : 'en-US';
251     }
252     return ilib.locale;
253 };
254 
255 /**
256  * Sets the default time zone for all of ilib. This time zone will be used when
257  * no explicit time zone is passed to any ilib class. If the default time zone
258  * is not set, ilib will attempt to use the time zone of the
259  * environment it is running in, if it can find that. If not, it will
260  * default to the the UTC zone "Etc/UTC".<p>
261  * 
262  * Depends directive: !depends ilibglobal.js
263  * 
264  * @static
265  * @param {string} tz the name of the time zone to set as the default time zone
266  */
267 ilib.setTimeZone = function (tz) {
268     ilib.tz = tz || ilib.tz;
269 };
270 
271 /**
272  * Return the default time zone for all of ilib if one has been set. This 
273  * time zone will be used when no explicit time zone is passed to any ilib 
274  * class. If the default time zone
275  * is not set, ilib will attempt to use the locale of the
276  * environment it is running in, if it can find that. If not, it will
277  * default to the the zone "local".<p>
278  * 
279  * Depends directive: !depends ilibglobal.js
280  * 
281  * @static
282  * @return {string} the default time zone for ilib
283  */
284 ilib.getTimeZone = function() {
285     if (typeof(ilib.tz) === 'undefined') {
286         if (typeof(navigator) !== 'undefined' && typeof(navigator.timezone) !== 'undefined') {
287             // running in a browser
288             if (navigator.timezone.length > 0) {
289                 ilib.tz = navigator.timezone;
290             }
291         } else if (typeof(PalmSystem) !== 'undefined' && typeof(PalmSystem.timezone) !== 'undefined') {
292             // running in webkit on webOS
293             if (PalmSystem.timezone.length > 0) {
294                 ilib.tz = PalmSystem.timezone;
295             }
296         } else if (typeof(environment) !== 'undefined' && typeof(environment.user) !== 'undefined') {
297             // running under rhino
298             if (typeof(environment.user.timezone) !== 'undefined' && environment.user.timezone.length > 0) {
299                 ilib.tz = environment.user.timezone;
300             }
301         } else if (typeof(process) !== 'undefined' && typeof(process.env) !== 'undefined') {
302             // running in nodejs
303             if (process.env.TZ && process.env.TZ !== "undefined") {
304                 ilib.tz = process.env.TZ;
305             }
306         }
307         
308         ilib.tz = ilib.tz || "local"; 
309     }
310 
311     return ilib.tz;
312 };
313 
314 /**
315  * @class
316  * Defines the interface for the loader class for ilib. The main method of the
317  * loader object is loadFiles(), which loads a set of requested locale data files
318  * from where-ever it is stored.
319  * @interface
320  */
321 ilib.Loader = function() {};
322 
323 /**
324  * Load a set of files from where-ever it is stored.<p>
325  * 
326  * This is the main function define a callback function for loading missing locale 
327  * data or resources.
328  * If this copy of ilib is assembled without including the required locale data
329  * or resources, then that data can be lazy loaded dynamically when it is 
330  * needed by calling this method. Each ilib class will first
331  * check for the existence of data under ilib.data, and if it is not there, 
332  * it will attempt to load it by calling this method of the laoder, and then place
333  * it there.<p>
334  * 
335  * Suggested implementations of this method might load files 
336  * directly from disk under nodejs or rhino, or within web pages, to load 
337  * files from the server with XHR calls.<p>
338  * 
339  * The first parameter to this method, paths, is an array of relative paths within 
340  * the ilib dir structure for the 
341  * requested data. These paths will already have the locale spec integrated 
342  * into them, so no further tweaking needs to happen to load the data. Simply
343  * load the named files. The second
344  * parameter tells the loader whether to load the files synchronously or asynchronously.
345  * If the sync parameters is false, then the onLoad function must also be specified.
346  * The third parameter gives extra parameters to the loader passed from the calling
347  * code. This may contain any property/value pairs.  The last parameter, callback,
348  * is a callback function to call when all of the data is finishing loading. Make
349  * sure to call the callback with the context of "this" so that the caller has their 
350  * context back again.<p>
351  * 
352  * The loader function must be able to operate either synchronously or asychronously. 
353  * If the loader function is called with an undefined callback function, it is
354  * expected to load the data synchronously, convert it to javascript
355  * objects, and return the array of json objects as the return value of the 
356  * function. If the loader 
357  * function is called with a callback function, it may load the data 
358  * synchronously or asynchronously (doesn't matter which) as long as it calls
359  * the callback function with the data converted to a javascript objects
360  * when it becomes available. If a particular file could not be loaded, the 
361  * loader function should put undefined into the corresponding entry in the
362  * results array. 
363  * Note that it is important that all the data is loaded before the callback
364  * is called.<p>
365  * 
366  * An example implementation for nodejs might be:
367  * 
368  * <pre>
369  * var fs = require("fs");
370  * 
371  * var myLoader = function() {};
372  * myLoader.prototype = new ilib.Loader();
373  * myLoader.prototype.constructor = myLoader;
374  * myLoader.prototype.loadFiles = function(paths, sync, params, callback) {
375  *    if (sync) {
376  *        var ret = [];
377  *        // synchronous load -- just return the result
378  *        paths.forEach(function (path) {
379  *            var json = fs.readFileSync(path, "utf-8");
380  *            ret.push(json ? JSON.parse(json) : undefined);
381  *        });
382  *        
383  *        return ret;
384  *    }
385  *    this.callback = callback;
386  *
387  *    // asynchronous
388  *    this.results = [];
389  *    this._loadFilesAsync(paths);
390  * }
391  * myLoader.prototype._loadFilesAsync = function (paths) {
392  *    if (paths.length > 0) {
393  *        var file = paths.shift();
394  *        fs.readFile(file, "utf-8", function(err, json) {
395  *            this.results.push(err ? undefined : JSON.parse(json));
396  *            // call self recursively so that the callback is only called at the end
397  *            // when all the files are loaded sequentially
398  *            if (paths.length > 0) {
399  *                this._loadFilesAsync(paths);
400  *            } else {
401  *                this.callback(this.results);
402  *            }
403  *        });
404  *     }
405  * }
406  * 
407  * // bind to "this" so that "this" is relative to your own instance
408  * ilib.setLoaderCallback(new myLoader());
409  * </pre>
410 
411  * @param {Array.<string>} paths An array of paths to load from wherever the files are stored 
412  * @param {Boolean} sync if true, load the files synchronously, and false means asynchronously
413  * @param {Object} params an object with any extra parameters for the loader. These can be 
414  * anything. The caller of the ilib class passes these parameters in. Presumably, the code that
415  * calls ilib and the code that provides the loader are together and can have a private 
416  * agreement between them about what the parameters should contain.
417  * @param {function(Object)} callback function to call when the files are all loaded. The 
418  * parameter of the callback function is the contents of the files.
419  */
420 ilib.Loader.prototype.loadFiles = function (paths, sync, params, callback) {};
421 
422 /**
423  * Return all files available for loading using this loader instance.
424  * This method returns an object where the properties are the paths to
425  * directories where files are loaded from and the values are an array
426  * of strings containing the relative paths under the directory of each
427  * file that can be loaded.<p>
428  * 
429  * Example:
430  *  <pre>
431  *  {
432  *      "/usr/share/javascript/ilib/locale": [
433  *          "dateformats.json",
434  *          "aa/dateformats.json",
435  *          "af/dateformats.json",
436  *          "agq/dateformats.json",
437  *          "ak/dateformats.json",
438  *          ...
439  *          "zxx/dateformats.json"
440  *      ]
441  *  }
442  *  </pre>
443  * @returns {Object} a hash containing directory names and
444  * paths to file that can be loaded by this loader 
445  */
446 ilib.Loader.prototype.listAvailableFiles = function() {};
447 
448 /**
449  * Return true if the file in the named path is available for loading using
450  * this loader. The path may be given as an absolute path, in which case
451  * only that file is checked, or as a relative path, in which case, the
452  * relative path may appear underneath any of the directories that the loader
453  * knows about.
454  * @returns {boolean} true if the file in the named path is available for loading, and
455  * false otherwise
456  */
457 ilib.Loader.prototype.isAvailable = function(path) {};
458 
459 /**
460  * Set the custom loader used to load ilib's locale data in your environment. 
461  * The instance passed in must implement the ilib.Loader interface. See the
462  * ilib.Loader class documentation for more information about loaders. 
463  * 
464  * @static
465  * @param {ilib.Loader} loader class to call to access the requested data.
466  * @return {boolean} true if the loader was installed correctly, or false
467  * if not
468  */
469 ilib.setLoaderCallback = function(loader) {
470     // only a basic check
471     if ((typeof(loader) === 'object' && loader instanceof ilib.Loader) || 
472             typeof(loader) === 'function' || typeof(loader) === 'undefined') {
473         // console.log("setting callback loader to " + (loader ? loader.name : "undefined"));
474         ilib._load = loader;
475         return true;
476     }
477     return false;
478 };
479 
480 /*
481  * locale.js - Locale specifier definition
482  * 
483  * Copyright © 2012-2014, JEDLSoft
484  *
485  * Licensed under the Apache License, Version 2.0 (the "License");
486  * you may not use this file except in compliance with the License.
487  * You may obtain a copy of the License at
488  *
489  *     http://www.apache.org/licenses/LICENSE-2.0
490  *
491  * Unless required by applicable law or agreed to in writing, software
492  * distributed under the License is distributed on an "AS IS" BASIS,
493  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
494  *
495  * See the License for the specific language governing permissions and
496  * limitations under the License.
497  */
498 
499 // !depends ilibglobal.js
500 
501 /**
502  * @class
503  * Create a new locale instance. Locales are specified either with a specifier string 
504  * that follows the BCP-47 convention (roughly: "language-region-script-variant") or 
505  * with 4 parameters that specify the language, region, variant, and script individually.<p>
506  * 
507  * The language is given as an ISO 639-1 two-letter, lower-case language code. You
508  * can find a full list of these codes at 
509  * <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>
510  * 
511  * The region is given as an ISO 3166-1 two-letter, upper-case region code. You can
512  * find a full list of these codes at 
513  * <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2</a>.<p>
514  * 
515  * The variant is any string that does not contain a dash which further differentiates
516  * locales from each other.<p>
517  * 
518  * The script is given as the ISO 15924 four-letter script code. In some locales,
519  * text may be validly written in more than one script. For example, Serbian is often
520  * written in both Latin and Cyrillic, though not usually mixed together. You can find a
521  * full list of these codes at 
522  * <a href="http://en.wikipedia.org/wiki/ISO_15924#List_of_codes">http://en.wikipedia.org/wiki/ISO_15924#List_of_codes</a>.<p>
523  * 
524  * As an example in ilib, the script can be used in the date formatter. Dates formatted 
525  * in Serbian could have day-of-week names or month names written in the Latin
526  * or Cyrillic script. Often one script is default such that sr-SR-Latn is the same
527  * as sr-SR so the script code "Latn" can be left off of the locale spec.<p> 
528  * 
529  * Each part is optional, and an empty string in the specifier before or after a 
530  * dash or as a parameter to the constructor denotes an unspecified value. In this
531  * case, many of the ilib functions will treat the locale as generic. For example
532  * the locale "en-" is equivalent to "en" and to "en--" and denotes a locale
533  * of "English" with an unspecified region and variant, which typically matches
534  * any region or variant.<p>
535  * 
536  * Without any arguments to the constructor, this function returns the locale of
537  * the host Javascript engine.<p>
538  * 
539  * Depends directive: !depends locale.js
540  * 
541  * @constructor
542  * @param {?string|ilib.Locale=} language the ISO 639 2-letter code for the language, or a full 
543  * locale spec in BCP-47 format, or another ilib.Locale instance to copy from
544  * @param {string=} region the ISO 3166 2-letter code for the region
545  * @param {string=} variant the name of the variant of this locale, if any
546  * @param {string=} script the ISO 15924 code of the script for this locale, if any
547  */
548 ilib.Locale = function(language, region, variant, script) {
549 	if (typeof(region) === 'undefined') {
550 		var spec = language || ilib.getLocale();
551 
552 		if (typeof(spec) === 'string') {
553 			var parts = spec.split('-');
554 
555 
556 	        for ( var i = 0; i < parts.length; i++ ) {
557 	        	if (ilib.Locale._isLanguageCode(parts[i])) {
558 	    			/** 
559 	    			 * @private
560 	    			 * @type {string|undefined}
561 	    			 */
562 	        		this.language = parts[i];
563 	        	} else if (ilib.Locale._isRegionCode(parts[i])) {
564 	    			/** 
565 	    			 * @private
566 	    			 * @type {string|undefined}
567 	    			 */
568 	        		this.region = parts[i];
569 	        	} else if (ilib.Locale._isScriptCode(parts[i])) {
570 	    			/** 
571 	    			 * @private
572 	    			 * @type {string|undefined}
573 	    			 */
574 	        		this.script = parts[i];
575 	        	} else {
576 	    			/** 
577 	    			 * @private
578 	    			 * @type {string|undefined}
579 	    			 */
580 	        		this.variant = parts[i];
581 	        	}
582 	        }
583 	        this.language = this.language || undefined;
584 	        this.region = this.region || undefined;
585 	        this.script = this.script || undefined;
586 	        this.variant = this.variant || undefined;
587 		} else if (typeof(spec) === 'object') {
588 	        this.language = spec.language || undefined;
589 	        this.region = spec.region || undefined;
590 	        this.script = spec.script || undefined;
591 	        this.variant = spec.variant || undefined;
592 		}
593 	} else {
594 		if (language) {
595 			language = language.trim();
596 			this.language = language.length > 0 ? language.toLowerCase() : undefined;
597 		} else {
598 			this.language = undefined;
599 		}
600 		if (region) {
601 			region = region.trim();
602 			this.region = region.length > 0 ? region.toUpperCase() : undefined;
603 		} else {
604 			this.region = undefined;
605 		}
606 		if (variant) {
607 			variant = variant.trim();
608 			this.variant = variant.length > 0 ? variant : undefined;
609 		} else {
610 			this.variant = undefined;
611 		}
612 		if (script) {
613 			script = script.trim();
614 			this.script = script.length > 0 ? script : undefined;
615 		} else {
616 			this.script = undefined;
617 		}
618 	}
619 	this._genSpec();
620 };
621 
622 // from http://en.wikipedia.org/wiki/ISO_3166-1
623 ilib.Locale.a2toa3regmap = {
624 	"AF": "AFG",
625 	"AX": "ALA",
626 	"AL": "ALB",
627 	"DZ": "DZA",
628 	"AS": "ASM",
629 	"AD": "AND",
630 	"AO": "AGO",
631 	"AI": "AIA",
632 	"AQ": "ATA",
633 	"AG": "ATG",
634 	"AR": "ARG",
635 	"AM": "ARM",
636 	"AW": "ABW",
637 	"AU": "AUS",
638 	"AT": "AUT",
639 	"AZ": "AZE",
640 	"BS": "BHS",
641 	"BH": "BHR",
642 	"BD": "BGD",
643 	"BB": "BRB",
644 	"BY": "BLR",
645 	"BE": "BEL",
646 	"BZ": "BLZ",
647 	"BJ": "BEN",
648 	"BM": "BMU",
649 	"BT": "BTN",
650 	"BO": "BOL",
651 	"BQ": "BES",
652 	"BA": "BIH",
653 	"BW": "BWA",
654 	"BV": "BVT",
655 	"BR": "BRA",
656 	"IO": "IOT",
657 	"BN": "BRN",
658 	"BG": "BGR",
659 	"BF": "BFA",
660 	"BI": "BDI",
661 	"KH": "KHM",
662 	"CM": "CMR",
663 	"CA": "CAN",
664 	"CV": "CPV",
665 	"KY": "CYM",
666 	"CF": "CAF",
667 	"TD": "TCD",
668 	"CL": "CHL",
669 	"CN": "CHN",
670 	"CX": "CXR",
671 	"CC": "CCK",
672 	"CO": "COL",
673 	"KM": "COM",
674 	"CG": "COG",
675 	"CD": "COD",
676 	"CK": "COK",
677 	"CR": "CRI",
678 	"CI": "CIV",
679 	"HR": "HRV",
680 	"CU": "CUB",
681 	"CW": "CUW",
682 	"CY": "CYP",
683 	"CZ": "CZE",
684 	"DK": "DNK",
685 	"DJ": "DJI",
686 	"DM": "DMA",
687 	"DO": "DOM",
688 	"EC": "ECU",
689 	"EG": "EGY",
690 	"SV": "SLV",
691 	"GQ": "GNQ",
692 	"ER": "ERI",
693 	"EE": "EST",
694 	"ET": "ETH",
695 	"FK": "FLK",
696 	"FO": "FRO",
697 	"FJ": "FJI",
698 	"FI": "FIN",
699 	"FR": "FRA",
700 	"GF": "GUF",
701 	"PF": "PYF",
702 	"TF": "ATF",
703 	"GA": "GAB",
704 	"GM": "GMB",
705 	"GE": "GEO",
706 	"DE": "DEU",
707 	"GH": "GHA",
708 	"GI": "GIB",
709 	"GR": "GRC",
710 	"GL": "GRL",
711 	"GD": "GRD",
712 	"GP": "GLP",
713 	"GU": "GUM",
714 	"GT": "GTM",
715 	"GG": "GGY",
716 	"GN": "GIN",
717 	"GW": "GNB",
718 	"GY": "GUY",
719 	"HT": "HTI",
720 	"HM": "HMD",
721 	"VA": "VAT",
722 	"HN": "HND",
723 	"HK": "HKG",
724 	"HU": "HUN",
725 	"IS": "ISL",
726 	"IN": "IND",
727 	"ID": "IDN",
728 	"IR": "IRN",
729 	"IQ": "IRQ",
730 	"IE": "IRL",
731 	"IM": "IMN",
732 	"IL": "ISR",
733 	"IT": "ITA",
734 	"JM": "JAM",
735 	"JP": "JPN",
736 	"JE": "JEY",
737 	"JO": "JOR",
738 	"KZ": "KAZ",
739 	"KE": "KEN",
740 	"KI": "KIR",
741 	"KP": "PRK",
742 	"KR": "KOR",
743 	"KW": "KWT",
744 	"KG": "KGZ",
745 	"LA": "LAO",
746 	"LV": "LVA",
747 	"LB": "LBN",
748 	"LS": "LSO",
749 	"LR": "LBR",
750 	"LY": "LBY",
751 	"LI": "LIE",
752 	"LT": "LTU",
753 	"LU": "LUX",
754 	"MO": "MAC",
755 	"MK": "MKD",
756 	"MG": "MDG",
757 	"MW": "MWI",
758 	"MY": "MYS",
759 	"MV": "MDV",
760 	"ML": "MLI",
761 	"MT": "MLT",
762 	"MH": "MHL",
763 	"MQ": "MTQ",
764 	"MR": "MRT",
765 	"MU": "MUS",
766 	"YT": "MYT",
767 	"MX": "MEX",
768 	"FM": "FSM",
769 	"MD": "MDA",
770 	"MC": "MCO",
771 	"MN": "MNG",
772 	"ME": "MNE",
773 	"MS": "MSR",
774 	"MA": "MAR",
775 	"MZ": "MOZ",
776 	"MM": "MMR",
777 	"NA": "NAM",
778 	"NR": "NRU",
779 	"NP": "NPL",
780 	"NL": "NLD",
781 	"NC": "NCL",
782 	"NZ": "NZL",
783 	"NI": "NIC",
784 	"NE": "NER",
785 	"NG": "NGA",
786 	"NU": "NIU",
787 	"NF": "NFK",
788 	"MP": "MNP",
789 	"NO": "NOR",
790 	"OM": "OMN",
791 	"PK": "PAK",
792 	"PW": "PLW",
793 	"PS": "PSE",
794 	"PA": "PAN",
795 	"PG": "PNG",
796 	"PY": "PRY",
797 	"PE": "PER",
798 	"PH": "PHL",
799 	"PN": "PCN",
800 	"PL": "POL",
801 	"PT": "PRT",
802 	"PR": "PRI",
803 	"QA": "QAT",
804 	"RE": "REU",
805 	"RO": "ROU",
806 	"RU": "RUS",
807 	"RW": "RWA",
808 	"BL": "BLM",
809 	"SH": "SHN",
810 	"KN": "KNA",
811 	"LC": "LCA",
812 	"MF": "MAF",
813 	"PM": "SPM",
814 	"VC": "VCT",
815 	"WS": "WSM",
816 	"SM": "SMR",
817 	"ST": "STP",
818 	"SA": "SAU",
819 	"SN": "SEN",
820 	"RS": "SRB",
821 	"SC": "SYC",
822 	"SL": "SLE",
823 	"SG": "SGP",
824 	"SX": "SXM",
825 	"SK": "SVK",
826 	"SI": "SVN",
827 	"SB": "SLB",
828 	"SO": "SOM",
829 	"ZA": "ZAF",
830 	"GS": "SGS",
831 	"SS": "SSD",
832 	"ES": "ESP",
833 	"LK": "LKA",
834 	"SD": "SDN",
835 	"SR": "SUR",
836 	"SJ": "SJM",
837 	"SZ": "SWZ",
838 	"SE": "SWE",
839 	"CH": "CHE",
840 	"SY": "SYR",
841 	"TW": "TWN",
842 	"TJ": "TJK",
843 	"TZ": "TZA",
844 	"TH": "THA",
845 	"TL": "TLS",
846 	"TG": "TGO",
847 	"TK": "TKL",
848 	"TO": "TON",
849 	"TT": "TTO",
850 	"TN": "TUN",
851 	"TR": "TUR",
852 	"TM": "TKM",
853 	"TC": "TCA",
854 	"TV": "TUV",
855 	"UG": "UGA",
856 	"UA": "UKR",
857 	"AE": "ARE",
858 	"GB": "GBR",
859 	"US": "USA",
860 	"UM": "UMI",
861 	"UY": "URY",
862 	"UZ": "UZB",
863 	"VU": "VUT",
864 	"VE": "VEN",
865 	"VN": "VNM",
866 	"VG": "VGB",
867 	"VI": "VIR",
868 	"WF": "WLF",
869 	"EH": "ESH",
870 	"YE": "YEM",
871 	"ZM": "ZMB",
872 	"ZW": "ZWE"
873 };
874 
875 
876 ilib.Locale.a1toa3langmap = {
877 	"ab": "abk",
878 	"aa": "aar",
879 	"af": "afr",
880 	"ak": "aka",
881 	"sq": "sqi",
882 	"am": "amh",
883 	"ar": "ara",
884 	"an": "arg",
885 	"hy": "hye",
886 	"as": "asm",
887 	"av": "ava",
888 	"ae": "ave",
889 	"ay": "aym",
890 	"az": "aze",
891 	"bm": "bam",
892 	"ba": "bak",
893 	"eu": "eus",
894 	"be": "bel",
895 	"bn": "ben",
896 	"bh": "bih",
897 	"bi": "bis",
898 	"bs": "bos",
899 	"br": "bre",
900 	"bg": "bul",
901 	"my": "mya",
902 	"ca": "cat",
903 	"ch": "cha",
904 	"ce": "che",
905 	"ny": "nya",
906 	"zh": "zho",
907 	"cv": "chv",
908 	"kw": "cor",
909 	"co": "cos",
910 	"cr": "cre",
911 	"hr": "hrv",
912 	"cs": "ces",
913 	"da": "dan",
914 	"dv": "div",
915 	"nl": "nld",
916 	"dz": "dzo",
917 	"en": "eng",
918 	"eo": "epo",
919 	"et": "est",
920 	"ee": "ewe",
921 	"fo": "fao",
922 	"fj": "fij",
923 	"fi": "fin",
924 	"fr": "fra",
925 	"ff": "ful",
926 	"gl": "glg",
927 	"ka": "kat",
928 	"de": "deu",
929 	"el": "ell",
930 	"gn": "grn",
931 	"gu": "guj",
932 	"ht": "hat",
933 	"ha": "hau",
934 	"he": "heb",
935 	"hz": "her",
936 	"hi": "hin",
937 	"ho": "hmo",
938 	"hu": "hun",
939 	"ia": "ina",
940 	"id": "ind",
941 	"ie": "ile",
942 	"ga": "gle",
943 	"ig": "ibo",
944 	"ik": "ipk",
945 	"io": "ido",
946 	"is": "isl",
947 	"it": "ita",
948 	"iu": "iku",
949 	"ja": "jpn",
950 	"jv": "jav",
951 	"kl": "kal",
952 	"kn": "kan",
953 	"kr": "kau",
954 	"ks": "kas",
955 	"kk": "kaz",
956 	"km": "khm",
957 	"ki": "kik",
958 	"rw": "kin",
959 	"ky": "kir",
960 	"kv": "kom",
961 	"kg": "kon",
962 	"ko": "kor",
963 	"ku": "kur",
964 	"kj": "kua",
965 	"la": "lat",
966 	"lb": "ltz",
967 	"lg": "lug",
968 	"li": "lim",
969 	"ln": "lin",
970 	"lo": "lao",
971 	"lt": "lit",
972 	"lu": "lub",
973 	"lv": "lav",
974 	"gv": "glv",
975 	"mk": "mkd",
976 	"mg": "mlg",
977 	"ms": "msa",
978 	"ml": "mal",
979 	"mt": "mlt",
980 	"mi": "mri",
981 	"mr": "mar",
982 	"mh": "mah",
983 	"mn": "mon",
984 	"na": "nau",
985 	"nv": "nav",
986 	"nb": "nob",
987 	"nd": "nde",
988 	"ne": "nep",
989 	"ng": "ndo",
990 	"nn": "nno",
991 	"no": "nor",
992 	"ii": "iii",
993 	"nr": "nbl",
994 	"oc": "oci",
995 	"oj": "oji",
996 	"cu": "chu",
997 	"om": "orm",
998 	"or": "ori",
999 	"os": "oss",
1000 	"pa": "pan",
1001 	"pi": "pli",
1002 	"fa": "fas",
1003 	"pl": "pol",
1004 	"ps": "pus",
1005 	"pt": "por",
1006 	"qu": "que",
1007 	"rm": "roh",
1008 	"rn": "run",
1009 	"ro": "ron",
1010 	"ru": "rus",
1011 	"sa": "san",
1012 	"sc": "srd",
1013 	"sd": "snd",
1014 	"se": "sme",
1015 	"sm": "smo",
1016 	"sg": "sag",
1017 	"sr": "srp",
1018 	"gd": "gla",
1019 	"sn": "sna",
1020 	"si": "sin",
1021 	"sk": "slk",
1022 	"sl": "slv",
1023 	"so": "som",
1024 	"st": "sot",
1025 	"az": "azb",
1026 	"es": "spa",
1027 	"su": "sun",
1028 	"sw": "swa",
1029 	"ss": "ssw",
1030 	"sv": "swe",
1031 	"ta": "tam",
1032 	"te": "tel",
1033 	"tg": "tgk",
1034 	"th": "tha",
1035 	"ti": "tir",
1036 	"bo": "bod",
1037 	"tk": "tuk",
1038 	"tl": "tgl",
1039 	"tn": "tsn",
1040 	"to": "ton",
1041 	"tr": "tur",
1042 	"ts": "tso",
1043 	"tt": "tat",
1044 	"tw": "twi",
1045 	"ty": "tah",
1046 	"ug": "uig",
1047 	"uk": "ukr",
1048 	"ur": "urd",
1049 	"uz": "uzb",
1050 	"ve": "ven",
1051 	"vi": "vie",
1052 	"vo": "vol",
1053 	"wa": "wln",
1054 	"cy": "cym",
1055 	"wo": "wol",
1056 	"fy": "fry",
1057 	"xh": "xho",
1058 	"yi": "yid",
1059 	"yo": "yor",
1060 	"za": "zha",
1061 	"zu": "zul"
1062 };
1063 
1064 /**
1065  * Tell whether or not the str does not start with a lower case ASCII char.
1066  * @private
1067  * @param {string} str the char to check
1068  * @return {boolean} true if the char is not a lower case ASCII char
1069  */
1070 ilib.Locale._notLower = function(str) {
1071 	// do this with ASCII only so we don't have to depend on the CType functions
1072 	var ch = str.charCodeAt(0);
1073 	return ch < 97 || ch > 122;
1074 };
1075 
1076 /**
1077  * Tell whether or not the str does not start with an upper case ASCII char.
1078  * @private
1079  * @param {string} str the char to check
1080  * @return {boolean} true if the char is a not an upper case ASCII char
1081  */
1082 ilib.Locale._notUpper = function(str) {
1083 	// do this with ASCII only so we don't have to depend on the CType functions
1084 	var ch = str.charCodeAt(0);
1085 	return ch < 65 || ch > 90;
1086 };
1087 
1088 /**
1089  * Tell whether or not the str does not start with a digit char.
1090  * @private
1091  * @param {string} str the char to check
1092  * @return {boolean} true if the char is a not an upper case ASCII char
1093  */
1094 ilib.Locale._notDigit = function(str) {
1095 	// do this with ASCII only so we don't have to depend on the CType functions
1096 	var ch = str.charCodeAt(0);
1097 	return ch < 48 || ch > 57;
1098 };
1099 
1100 /**
1101  * Tell whether or not the given string has the correct syntax to be 
1102  * an ISO 639 language code.
1103  * 
1104  * @private
1105  * @param {string} str the string to parse
1106  * @return {boolean} true if the string could syntactically be a language code.
1107  */
1108 ilib.Locale._isLanguageCode = function(str) {
1109 	if (typeof(str) === 'undefined' || str.length < 2 || str.length > 3) {
1110 		return false;
1111 	}
1112 
1113 	for (var i = 0; i < str.length; i++) {
1114 		if (ilib.Locale._notLower(str.charAt(i))) {
1115 			return false;
1116 		}
1117 	}
1118 	
1119 	return true;
1120 };
1121 
1122 /**
1123  * Tell whether or not the given string has the correct syntax to be 
1124  * an ISO 3166 2-letter region code or M.49 3-digit region code.
1125  * 
1126  * @private
1127  * @param {string} str the string to parse
1128  * @return {boolean} true if the string could syntactically be a language code.
1129  */
1130 ilib.Locale._isRegionCode = function (str) {
1131 	if (typeof(str) === 'undefined' || str.length < 2 || str.length > 3) {
1132 		return false;
1133 	}
1134 	
1135 	if (str.length === 2) {
1136 		for (var i = 0; i < str.length; i++) {
1137 			if (ilib.Locale._notUpper(str.charAt(i))) {
1138 				return false;
1139 			}
1140 		}
1141 	} else {
1142 		for (var i = 0; i < str.length; i++) {
1143 			if (ilib.Locale._notDigit(str.charAt(i))) {
1144 				return false;
1145 			}
1146 		}
1147 	}
1148 	
1149 	return true;
1150 };
1151 
1152 /**
1153  * Tell whether or not the given string has the correct syntax to be 
1154  * an ISO 639 language code.
1155  * 
1156  * @private
1157  * @param {string} str the string to parse
1158  * @return {boolean} true if the string could syntactically be a language code.
1159  */
1160 ilib.Locale._isScriptCode = function(str)
1161 {
1162 	if (typeof(str) === 'undefined' || str.length !== 4 || ilib.Locale._notUpper(str.charAt(0))) {
1163 		return false;
1164 	}
1165 	
1166 	for (var i = 1; i < 4; i++) {
1167 		if (ilib.Locale._notLower(str.charAt(i))) {
1168 			return false;
1169 		}
1170 	}
1171 	
1172 	return true;
1173 };
1174 
1175 /**
1176  * Return the ISO-3166 alpha3 equivalent region code for the given ISO 3166 alpha2
1177  * region code. If the given alpha2 code is not found, this function returns its
1178  * argument unchanged.
1179  * @static
1180  * @param {string|undefined} alpha2 the alpha2 code to map
1181  * @return {string|undefined} the alpha3 equivalent of the given alpha2 code, or the alpha2
1182  * parameter if the alpha2 value is not found
1183  */
1184 ilib.Locale.regionAlpha2ToAlpha3 = function(alpha2) {
1185 	return ilib.Locale.a2toa3regmap[alpha2] || alpha2;
1186 };
1187 
1188 /**
1189  * Return the ISO-639 alpha3 equivalent language code for the given ISO 639 alpha1
1190  * language code. If the given alpha1 code is not found, this function returns its
1191  * argument unchanged.
1192  * @static
1193  * @param {string|undefined} alpha1 the alpha1 code to map
1194  * @return {string|undefined} the alpha3 equivalent of the given alpha1 code, or the alpha1
1195  * parameter if the alpha1 value is not found
1196  */
1197 ilib.Locale.languageAlpha1ToAlpha3 = function(alpha1) {
1198 	return ilib.Locale.a1toa3langmap[alpha1] || alpha1;
1199 };
1200 
1201 ilib.Locale.prototype = {
1202 	/**
1203 	 * @private
1204 	 */
1205 	_genSpec: function () {
1206 		this.spec = this.language || "";
1207 		
1208 		if (this.script) {
1209 			if (this.spec.length > 0) {
1210 				this.spec += "-";
1211 			}
1212 			this.spec += this.script;
1213 		}
1214 		
1215 		if (this.region) {
1216 			if (this.spec.length > 0) {
1217 				this.spec += "-";
1218 			}
1219 			this.spec += this.region;
1220 		}
1221 		
1222 		if (this.variant) {
1223 			if (this.spec.length > 0) {
1224 				this.spec += "-";
1225 			}
1226 			this.spec += this.variant;
1227 		}
1228 	},
1229 
1230 	/**
1231 	 * Return the ISO 639 language code for this locale. 
1232 	 * @return {string|undefined} the language code for this locale 
1233 	 */
1234 	getLanguage: function() {
1235 		return this.language;
1236 	},
1237 	
1238 	/**
1239 	 * Return the language of this locale as an ISO-639-alpha3 language code
1240 	 * @return {string|undefined} the alpha3 language code of this locale
1241 	 */
1242 	getLanguageAlpha3: function() {
1243 		return ilib.Locale.languageAlpha1ToAlpha3(this.language);
1244 	},
1245 	
1246 	/**
1247 	 * Return the ISO 3166 region code for this locale.
1248 	 * @return {string|undefined} the region code of this locale
1249 	 */
1250 	getRegion: function() {
1251 		return this.region;
1252 	},
1253 	
1254 	/**
1255 	 * Return the region of this locale as an ISO-3166-alpha3 region code
1256 	 * @return {string|undefined} the alpha3 region code of this locale
1257 	 */
1258 	getRegionAlpha3: function() {
1259 		return ilib.Locale.regionAlpha2ToAlpha3(this.region);
1260 	},
1261 	
1262 	/**
1263 	 * Return the ISO 15924 script code for this locale
1264 	 * @return {string|undefined} the script code of this locale
1265 	 */
1266 	getScript: function () {
1267 		return this.script;
1268 	},
1269 	
1270 	/**
1271 	 * Return the variant code for this locale
1272 	 * @return {string|undefined} the variant code of this locale, if any
1273 	 */
1274 	getVariant: function() {
1275 		return this.variant;
1276 	},
1277 	
1278 	/**
1279 	 * Return the whole locale specifier as a string.
1280 	 * @return {string} the locale specifier
1281 	 */
1282 	getSpec: function() {
1283 		return this.spec;
1284 	},
1285 	
1286 	/**
1287 	 * Express this locale object as a string. Currently, this simply calls the getSpec
1288 	 * function to represent the locale as its specifier.
1289 	 * 
1290 	 * @return {string} the locale specifier
1291 	 */
1292 	toString: function() {
1293 		return this.getSpec();
1294 	},
1295 	
1296 	/**
1297 	 * Return true if the the other locale is exactly equal to the current one.
1298 	 * @return {boolean} whether or not the other locale is equal to the current one 
1299 	 */
1300 	equals: function(other) {
1301 		return this.language === other.language &&
1302 			this.region === other.region &&
1303 			this.script === other.script &&
1304 			this.variant === other.variant;
1305 	},
1306 
1307 	/**
1308 	 * Return true if the current locale is the special pseudo locale.
1309 	 * @return {boolean} true if the current locale is the special pseudo locale
1310 	 */
1311 	isPseudo: function () {
1312 		var localeName = this.language + "-" + this.region;
1313 		return ilib.pseudoLocales.indexOf(localeName) > -1;
1314 	}
1315 };
1316 
1317 // static functions
1318 /**
1319  * @private
1320  */
1321 ilib.Locale.locales = [
1322 	
1323 ];
1324 
1325 /**
1326  * Return the list of available locales that this iLib file was assembled
1327  * with. The list that this file was assembled with may be much smaller
1328  * than the list of all available locales in the iLib repository. The
1329  * assembly tool will automatically fill in the list.
1330  * 
1331  * @return {Array.<string>} this is an array of locale specs for which 
1332  * this iLib file has locale data for
1333  */
1334 ilib.Locale.getAvailableLocales = function () {
1335 	return ilib.Locale.locales;
1336 };
1337 
1338 /*
1339  * localeinfo.js - Encode locale-specific defaults
1340  * 
1341  * Copyright © 2012-2014, JEDLSoft
1342  *
1343  * Licensed under the Apache License, Version 2.0 (the "License");
1344  * you may not use this file except in compliance with the License.
1345  * You may obtain a copy of the License at
1346  *
1347  *     http://www.apache.org/licenses/LICENSE-2.0
1348  *
1349  * Unless required by applicable law or agreed to in writing, software
1350  * distributed under the License is distributed on an "AS IS" BASIS,
1351  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1352  *
1353  * See the License for the specific language governing permissions and
1354  * limitations under the License.
1355  */
1356 
1357 // !depends ilibglobal.js locale.js
1358 
1359 // !data localeinfo
1360 
1361 /**
1362  * @class
1363  * Create a new locale info instance. Locale info instances give information about
1364  * the default settings for a particular locale. These settings may be overridden
1365  * by various parts of the code, and should be used as a fall-back setting of last
1366  * resort. <p>
1367  * 
1368  * The optional options object holds extra parameters if they are necessary. The
1369  * current list of supported options are:
1370  * 
1371  * <ul>
1372  * <li><i>onLoad</i> - a callback function to call when the locale info object is fully 
1373  * loaded. When the onLoad option is given, the localeinfo object will attempt to
1374  * load any missing locale data using the ilib loader callback.
1375  * When the constructor is done (even if the data is already preassembled), the 
1376  * onLoad function is called with the current instance as a parameter, so this
1377  * callback can be used with preassembled or dynamic loading or a mix of the two.
1378  * 
1379  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
1380  * asynchronously. If this option is given as "false", then the "onLoad"
1381  * callback must be given, as the instance returned from this constructor will
1382  * not be usable for a while. 
1383  *
1384  * <li><i>loadParams</i> - an object containing parameters to pass to the 
1385  * loader callback function when locale data is missing. The parameters are not
1386  * interpretted or modified in any way. They are simply passed along. The object 
1387  * may contain any property/value pairs as long as the calling code is in
1388  * agreement with the loader callback function as to what those parameters mean.
1389  * </ul>
1390  * 
1391  * If this copy of ilib is pre-assembled and all the data is already available, 
1392  * or if the data was already previously loaded, then this constructor will call
1393  * the onLoad callback immediately when the initialization is done. 
1394  * If the onLoad option is not given, this class will only attempt to load any
1395  * missing locale data synchronously.
1396  * 
1397  * Depends directive: !depends localeinfo.js
1398  * 
1399  * @constructor
1400  * @see {ilib.setLoaderCallback} for information about registering a loader callback
1401  * function
1402  * @param {ilib.Locale|string=} locale the locale for which the info is sought, or undefined for
1403  * @param {Object=} options the locale for which the info is sought, or undefined for
1404  * the current locale
1405  */
1406 ilib.LocaleInfo = function(locale, options) {
1407 	var sync = true,
1408 	    loadParams = undefined;
1409 	
1410 	/* these are all the defaults. Essentially, en-US */
1411 	/**
1412 	  @private 
1413 	  @type {{
1414 		scripts:Array.<string>,
1415 		timezone:string,
1416 		units:string,
1417 		calendar:string,
1418 		clock:string,
1419 		currency:string,
1420 		firstDayOfWeek:number,
1421 		weekendStart:number,
1422 		weekendEnd:number,
1423 		meridiems:string,
1424 		unitfmt: {long:string,short:string},
1425 		numfmt:Object.<{
1426 			currencyFormats:Object.<{common:string,commonNegative:string,iso:string,isoNegative:string}>,
1427 			script:string,
1428 			decimalChar:string,
1429 			groupChar:string,
1430 			prigroupSize:number,
1431 			secgroupSize:number,
1432 			negativenumFmt:string,
1433 			pctFmt:string,
1434 			negativepctFmt:string,
1435 			pctChar:string,
1436 			roundingMode:string,
1437 			exponential:string,
1438 			digits:string
1439 		}>
1440 	  }}
1441 	*/
1442 	this.info = ilib.LocaleInfo.defaultInfo;
1443 	
1444 	switch (typeof(locale)) {
1445 		case "string":
1446 			this.locale = new ilib.Locale(locale);
1447 			break;
1448 		default:
1449 		case "undefined":
1450 			this.locale = new ilib.Locale();
1451 			break;
1452 		case "object":
1453 			this.locale = locale;
1454 			break;
1455 	}
1456 	
1457 	if (options) {
1458 		if (typeof(options.sync) !== 'undefined') {
1459 			sync = (options.sync == true);
1460 		}
1461 		
1462 		if (typeof(options.loadParams) !== 'undefined') {
1463 			loadParams = options.loadParams;
1464 		}
1465 	}
1466 
1467 	if (!ilib.LocaleInfo.cache) {
1468 		ilib.LocaleInfo.cache = {};
1469 	}
1470 
1471 	ilib.loadData({
1472 		object: ilib.LocaleInfo, 
1473 		locale: this.locale, 
1474 		name: "localeinfo.json", 
1475 		sync: sync, 
1476 		loadParams: loadParams, 
1477 		callback: ilib.bind(this, function (info) {
1478 			if (!info) {
1479 				info = ilib.LocaleInfo.defaultInfo;
1480 				var spec = this.locale.getSpec().replace(/-/g, "_");
1481 				ilib.LocaleInfo.cache[spec] = info;
1482 			}
1483 			this.info = info;
1484 			if (options && typeof(options.onLoad) === 'function') {
1485 				options.onLoad(this);
1486 			}
1487 		})
1488 	});
1489 };
1490 
1491 ilib.LocaleInfo.defaultInfo = /** @type {{
1492 	scripts:Array.<string>,
1493 	timezone:string,
1494 	units:string,
1495 	calendar:string,
1496 	clock:string,
1497 	currency:string,
1498 	firstDayOfWeek:number,
1499 	weekendStart:number,
1500 	weekendEnd:number,
1501 	meridiems:string,
1502 	unitfmt: {long:string,short:string},
1503 	numfmt:Object.<{
1504 		currencyFormats:Object.<{
1505 			common:string,
1506 			commonNegative:string,
1507 			iso:string,
1508 			isoNegative:string
1509 		}>,
1510 		script:string,
1511 		decimalChar:string,
1512 		groupChar:string,
1513 		prigroupSize:number,
1514 		secgroupSize:number,
1515 		negativenumFmt:string,
1516 		pctFmt:string,
1517 		negativepctFmt:string,
1518 		pctChar:string,
1519 		roundingMode:string,
1520 		exponential:string,
1521 		digits:string
1522 	}>
1523 }}*/ ilib.data.localeinfo;
1524 ilib.LocaleInfo.defaultInfo = ilib.LocaleInfo.defaultInfo || {
1525 	"scripts": ["Latn"],
1526     "timezone": "Etc/UTC",
1527     "units": "metric",
1528     "calendar": "gregorian",
1529     "clock": "24",
1530     "currency": "USD",
1531     "firstDayOfWeek": 1,
1532     "meridiems": "gregorian",
1533     "numfmt": {
1534         "currencyFormats": {
1535             "common": "{s}{n}",
1536             "commonNegative": "{s}-{n}",
1537             "iso": "{s}{n}",
1538             "isoNegative": "{s}-{n}"
1539         },
1540         "script": "Latn",
1541         "decimalChar": ",",
1542         "groupChar": ".",
1543         "prigroupSize": 3,
1544         "secgroupSize": 0,
1545         "pctFmt": "{n}%",
1546         "negativepctFmt": "-{n}%",
1547         "pctChar": "%",
1548         "roundingMode": "halfdown",
1549         "exponential": "e",
1550         "digits": ""
1551     }
1552 };
1553 
1554 ilib.LocaleInfo.prototype = {
1555     /**
1556      * Return the name of the locale's language in English.
1557      * @returns {string} the name of the locale's language in English
1558      */
1559     getLanguageName: function () {
1560     	return this.info["language.name"];	
1561     },
1562     
1563     /**
1564      * Return the name of the locale's region in English. If the locale
1565      * has no region, this returns undefined.
1566      * 
1567      * @returns {string|undefined} the name of the locale's region in English
1568      */
1569     getRegionName: function () {
1570     	return this.info["region.name"];	
1571     },
1572 
1573     /**
1574 	 * Return whether this locale commonly uses the 12- or the 24-hour clock.
1575 	 *  
1576 	 * @returns {string} "12" if the locale commonly uses a 12-hour clock, or "24"
1577 	 * if the locale commonly uses a 24-hour clock. 
1578 	 */
1579 	getClock: function() {
1580 		return this.info.clock;
1581 	},
1582 
1583 	/**
1584 	 * Return the locale that this info object was created with.
1585 	 * @returns {ilib.Locale} The locale spec of the locale used to construct this info instance
1586 	 */
1587 	getLocale: function () {
1588 		return this.locale;
1589 	},
1590 	
1591 	/**
1592 	 * Return the name of the measuring system that is commonly used in the given locale.
1593 	 * Valid values are "uscustomary", "imperial", and "metric".
1594 	 * 
1595 	 * @returns {string} The name of the measuring system commonly used in the locale
1596 	 */
1597 	getUnits: function () {
1598 		return this.info.units;
1599 	},
1600         
1601         getUnitFormat: function () {
1602                 return this.info.unitfmt;
1603         },
1604 	
1605 	/**
1606 	 * Return the name of the calendar that is commonly used in the given locale.
1607 	 * 
1608 	 * @returns {string} The name of the calendar commonly used in the locale
1609 	 */
1610 	getCalendar: function () {
1611 		return this.info.calendar;
1612 	},
1613 	
1614 	/**
1615 	 * Return the day of week that starts weeks in the current locale. Days are still
1616 	 * numbered the standard way with 0 for Sunday through 6 for Saturday, but calendars 
1617 	 * should be displayed and weeks calculated with the day of week returned from this 
1618 	 * function as the first day of the week.
1619 	 * 
1620 	 * @returns {number} the day of the week that starts weeks in the current locale.
1621 	 */
1622 	getFirstDayOfWeek: function () {
1623 		return this.info.firstDayOfWeek;
1624 	},
1625 	
1626 	/**
1627 	 * Return the day of week that starts weekend in the current locale. Days are still
1628 	 * numbered the standard way with 0 for Sunday through 6 for Saturday.
1629 	 * 
1630 	 * @returns {number} the day of the week that starts weeks in the current locale.
1631 	 */
1632 	getWeekEndStart: function () {
1633 		return this.info.weekendStart;
1634 	},
1635 
1636 	/**
1637 	 * Return the day of week that starts weekend in the current locale. Days are still
1638 	 * numbered the standard way with 0 for Sunday through 6 for Saturday.
1639 	 * 
1640 	 * @returns {number} the day of the week that starts weeks in the current locale.
1641 	 */
1642 	getWeekEndEnd: function () {
1643 		return this.info.weekendEnd;
1644 	},
1645 
1646 	/**
1647 	 * Return the default time zone for this locale. Many locales span across multiple
1648 	 * time zones. In this case, the time zone with the largest population is chosen
1649 	 * to represent the locale. This is obviously not that accurate, but then again,
1650 	 * this method's return value should only be used as a default anyways.
1651 	 * @returns {string} the default time zone for this locale.
1652 	 */
1653 	getTimeZone: function () {
1654 		return this.info.timezone;
1655 	},
1656 	
1657 	/**
1658 	 * Return the decimal separator for formatted numbers in this locale.
1659 	 * @returns {string} the decimal separator char
1660 	 */
1661 	getDecimalSeparator: function () {
1662 		return this.info.numfmt.decimalChar;
1663 	},
1664 	
1665 	/**
1666 	 * Return the decimal separator for formatted numbers in this locale for native script.
1667 	 * @returns {string} the decimal separator char
1668 	 */
1669 	getNativeDecimalSeparator: function () {
1670 		return (this.info.native_numfmt && this.info.native_numfmt.decimalChar) || this.info.numfmt.decimalChar;
1671 	},
1672 	
1673 	/**
1674 	 * Return the separator character used to separate groups of digits on the 
1675 	 * integer side of the decimal character.
1676 	 * @returns {string} the grouping separator char
1677 	 */
1678 	getGroupingSeparator: function () {
1679 		return this.info.numfmt.groupChar;
1680 	},
1681 
1682 	/**
1683 	 * Return the separator character used to separate groups of digits on the 
1684 	 * integer side of the decimal character for the native script if present other than the default script.
1685 	 * @returns {string} the grouping separator char
1686 	 */
1687 	getNativeGroupingSeparator: function () {
1688 		return (this.info.native_numfmt && this.info.native_numfmt.groupChar) || this.info.numfmt.groupChar;
1689 	},
1690 	
1691 	/**
1692 	 * Return the minimum number of digits grouped together on the integer side 
1693 	 * for the first (primary) group. 
1694 	 * In western European cultures, groupings are in 1000s, so the number of digits
1695 	 * is 3. 
1696 	 * @returns {number} the number of digits in a primary grouping, or 0 for no grouping
1697 	 */
1698 	getPrimaryGroupingDigits: function () {
1699 		return (typeof(this.info.numfmt.prigroupSize) !== 'undefined' && this.info.numfmt.prigroupSize) || 0;
1700 	},
1701 
1702 	/**
1703 	 * Return the minimum number of digits grouped together on the integer side
1704 	 * for the second or more (secondary) group.<p>
1705 	 *   
1706 	 * In western European cultures, all groupings are by 1000s, so the secondary
1707 	 * size should be 0 because there is no secondary size. In general, if this 
1708 	 * method returns 0, then all groupings are of the primary size.<p> 
1709 	 * 
1710 	 * For some other cultures, the first grouping (primary)
1711 	 * is 3 and any subsequent groupings (secondary) are two. So, 100000 would be
1712 	 * written as: "1,00,000".
1713 	 * 
1714 	 * @returns {number} the number of digits in a secondary grouping, or 0 for no 
1715 	 * secondary grouping. 
1716 	 */
1717 	getSecondaryGroupingDigits: function () {
1718 		return this.info.numfmt.secgroupSize || 0;
1719 	},
1720 
1721 	/**
1722 	 * Return the format template used to format percentages in this locale.
1723 	 * @returns {string} the format template for formatting percentages
1724 	 */
1725 	getPercentageFormat: function () {
1726 		return this.info.numfmt.pctFmt;
1727 	},
1728 
1729 	/**
1730 	 * Return the format template used to format percentages in this locale
1731 	 * with negative amounts.
1732 	 * @returns {string} the format template for formatting percentages
1733 	 */
1734 	getNegativePercentageFormat: function () {
1735 		return this.info.numfmt.negativepctFmt;
1736 	},
1737 
1738 	/**
1739 	 * Return the symbol used for percentages in this locale.
1740 	 * @returns {string} the symbol used for percentages in this locale
1741 	 */
1742 	getPercentageSymbol: function () {
1743 		return this.info.numfmt.pctChar || "%";
1744 	},
1745 
1746 	/**
1747 	 * Return the symbol used for exponential in this locale.
1748 	 * @returns {string} the symbol used for exponential in this locale
1749 	 */
1750 	getExponential: function () {
1751 		return this.info.numfmt.exponential;
1752 	},
1753 
1754 	/**
1755 	 * Return the symbol used for exponential in this locale for native script.
1756 	 * @returns {string} the symbol used for exponential in this locale for native script
1757 	 */
1758 	getNativeExponential: function () {
1759 		return (this.info.native_numfmt && this.info.native_numfmt.exponential) || this.info.numfmt.exponential;
1760 	},
1761 
1762 	/**
1763 	 * Return the symbol used for percentages in this locale for native script.
1764 	 * @returns {string} the symbol used for percentages in this locale for native script
1765 	 */
1766 	getNativePercentageSymbol: function () {
1767 		return (this.info.native_numfmt && this.info.native_numfmt.pctChar) || this.info.numfmt.pctChar || "%";
1768 	
1769 	},
1770 	/**
1771 	 * Return the format template used to format negative numbers in this locale.
1772 	 * @returns {string} the format template for formatting negative numbers
1773 	 */
1774 	getNegativeNumberFormat: function () { 
1775 		return this.info.numfmt.negativenumFmt;
1776 	},
1777 	
1778 	/**
1779 	 * Return an object containing the format templates for formatting currencies
1780 	 * in this locale. The object has a number of properties in it that each are
1781 	 * a particular style of format. Normally, this contains a "common" and an "iso"
1782 	 * style, but may contain others in the future.
1783 	 * @returns {Object} an object containing the format templates for currencies
1784 	 */
1785 	getCurrencyFormats: function () {
1786 		return this.info.numfmt.currencyFormats;
1787 	},
1788 	
1789 	/**
1790 	 * Return the currency that is legal in the locale, or which is most commonly 
1791 	 * used in regular commerce.
1792 	 * @returns {string} the ISO 4217 code for the currency of this locale
1793 	 */
1794 	getCurrency: function () {
1795 		return this.info.currency;
1796 	},
1797 	
1798 	/**
1799 	 * Return a string that describes the style of digits used by this locale.
1800 	 * Possible return values are:
1801 	 * <ul>
1802 	 * <li><i>western</i> - uses the regular western 10-based digits 0 through 9
1803 	 * <li><i>optional</i> - native 10-based digits exist, but in modern usage,
1804 	 * this locale most often uses western digits
1805 	 * <li><i>native</i> - native 10-based native digits exist and are used
1806 	 * regularly by this locale
1807 	 * <li><i>custom</i> - uses native digits by default that are not 10-based
1808 	 * </ul>
1809 	 * @returns {string} string that describes the style of digits used in this locale
1810 	 */
1811 	getDigitsStyle: function () {
1812 		if (this.info.numfmt.useNative) {
1813 			return "native";
1814 		}
1815 		if (typeof(this.info.native_numfmt) !== 'undefined') {
1816 			return "optional";
1817 		}
1818 		return "western";
1819 	},
1820 	
1821 	/**
1822 	 * Return the digits of the default script if they are defined.
1823 	 * If not defined, the default should be the regular "Arabic numerals"
1824 	 * used in the Latin script. (0-9)
1825 	 * @returns {string|undefined} the digits used in the default script 
1826 	 */
1827 	getDigits: function () {
1828 		return this.info.numfmt.digits;
1829 	},
1830 	
1831 	/**
1832 	 * Return the digits of the native script if they are defined. 
1833 	 * @returns {string|undefined} the digits used in the default script 
1834 	 */
1835 	getNativeDigits: function () {
1836 		return (this.info.numfmt.useNative && this.info.numfmt.digits) || (this.info.native_numfmt && this.info.native_numfmt.digits);
1837 	},
1838 	
1839 	/**
1840 	 * If this locale typically uses a different type of rounding for numeric
1841 	 * formatting other than halfdown, especially for currency, then it can be 
1842 	 * specified in the localeinfo. If the locale uses the default, then this 
1843 	 * method returns undefined. The locale's rounding method overrides the 
1844 	 * rounding method for the currency itself, which can sometimes shared 
1845 	 * between various locales so it is less specific.
1846 	 * @returns {string} the name of the rounding mode typically used in this
1847 	 * locale, or "halfdown" if the locale does not override the default
1848 	 */
1849 	getRoundingMode: function () {
1850 		return this.info.numfmt.roundingMode;
1851 	},
1852 	
1853 	/**
1854 	 * Return the default script used to write text in the language of this 
1855 	 * locale. Text for most languages is written in only one script, but there
1856 	 * are some languages where the text can be written in a number of scripts,
1857 	 * depending on a variety of things such as the region, ethnicity, religion, 
1858 	 * etc. of the author. This method returns the default script for the
1859 	 * locale, in which the language is most commonly written.<p> 
1860 	 * 
1861 	 * The script is returned as an ISO 15924 4-letter code.
1862 	 * 
1863 	 * @returns {string} the ISO 15924 code for the default script used to write
1864 	 * text in this locale 
1865 	 */
1866 	getDefaultScript: function() {
1867 		return (this.info.scripts) ? this.info.scripts[0] : "Latn";
1868 	},
1869 	
1870 	/**
1871 	 * Return the script used for the current locale. If the current locale
1872 	 * explicitly defines a script, then this script is returned. If not, then 
1873 	 * the default script for the locale is returned.
1874 	 * 
1875 	 * @see ilib.LocaleInfo.getDefaultScript
1876 	 * @returns {string} the ISO 15924 code for the script used to write
1877 	 * text in this locale
1878 	 */
1879 	getScript: function() {
1880 		return this.locale.getScript() || this.getDefaultScript(); 
1881 	},
1882 	
1883 	/**
1884 	 * Return an array of script codes which are used to write text in the current
1885 	 * language. Text for most languages is written in only one script, but there
1886 	 * are some languages where the text can be written in a number of scripts,
1887 	 * depending on a variety of things such as the region, ethnicity, religion, 
1888 	 * etc. of the author. This method returns an array of script codes in which 
1889 	 * the language is commonly written.
1890 	 * 
1891 	 * @returns {Array.<string>} an array of ISO 15924 codes for the scripts used 
1892 	 * to write text in this language
1893 	 */
1894 	getAllScripts: function() {
1895 		return this.info.scripts || ["Latn"];
1896 	},
1897 	
1898 	/**
1899 	 * Return the default style of meridiems used in this locale. Meridiems are 
1900 	 * times of day like AM/PM. In a few locales with some calendars, for example
1901 	 * Amharic/Ethiopia using the Ethiopic calendar, the times of day may be
1902 	 * split into different segments than simple AM/PM as in the Gregorian 
1903 	 * calendar. Only a few locales are like that. For most locales, formatting 
1904 	 * a Gregorian date will use the regular Gregorian AM/PM meridiems.
1905 	 *  
1906 	 * @returns {string} the default meridiems style used in this locale. Possible
1907 	 * values are "gregorian", "chinese", and "ethiopic"
1908 	 */
1909 	getMeridiemsStyle: function () {
1910 		return this.info.meridiems || "gregorian";
1911 	}	
1912 };
1913 
1914 /*
1915  * date.js - Represent a date in any calendar. This class is subclassed for each calendar.
1916  * 
1917  * Copyright © 2012-2014, JEDLSoft
1918  *
1919  * Licensed under the Apache License, Version 2.0 (the "License");
1920  * you may not use this file except in compliance with the License.
1921  * You may obtain a copy of the License at
1922  *
1923  *     http://www.apache.org/licenses/LICENSE-2.0
1924  *
1925  * Unless required by applicable law or agreed to in writing, software
1926  * distributed under the License is distributed on an "AS IS" BASIS,
1927  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1928  *
1929  * See the License for the specific language governing permissions and
1930  * limitations under the License.
1931  */
1932 
1933 /* !depends ilibglobal.js localeinfo.js */
1934 
1935 /**
1936  * @class
1937  * Construct a new date object. Each parameter is a numeric value, but its 
1938  * accepted range can vary depending on the subclass of this date. For example,
1939  * Gregorian months can be from 1 to 12, whereas months in the Hebrew calendar
1940  * can be from 1 to 13.<p>
1941  * 
1942  * Note that this really calls the newInstance factory method underneath in 
1943  * order to instantiate the correct subclass of ilib.Date.
1944  * 
1945  * Depends directive: !depends date.js
1946  * 
1947  * @constructor
1948  * @param {Object=} options The date components to initialize this date with
1949  */
1950 ilib.Date = function(options) {
1951 	if (!options || typeof(options.noinstance) === 'undefined') {
1952 		return ilib.Date.newInstance(options);
1953 	}
1954 };
1955 
1956 /**
1957  * Factory method to create a new instance of a date subclass.<p>
1958  * 
1959  * The options parameter can be an object that contains the following
1960  * properties:
1961  * 
1962  * <ul>
1963  * <li><i>type</i> - specify the type/calendar of the date desired. The
1964  * list of valid values changes depending on which calendars are 
1965  * defined. When assembling your iliball.js, include those date type 
1966  * you wish to use in your program or web page, and they will register 
1967  * themselves with this factory method. The "gregorian",
1968  * and "julian" calendars are all included by default, as they are the
1969  * standard calendars for much of the world. If not specified, the type
1970  * of the date returned is the one that is appropriate for the locale.
1971  * This property may also be given as "calendar" instead of "type".
1972  * </ul>
1973  * 
1974  * The options object is also passed down to the date constructor, and 
1975  * thus can contain the the properties as the date object being instantiated.
1976  * See the documentation for {@link ilib.Date.GregDate}, and other
1977  * subclasses for more details on other parameter that may be passed in.<p>
1978  * 
1979  * Please note that if you do not give the type parameter, this factory
1980  * method will create a date object that is appropriate for the calendar
1981  * that is most commonly used in the specified or current ilib locale. 
1982  * For example, in Thailand, the most common calendar is the Thai solar 
1983  * calendar. If the current locale is "th-TH" (Thai for Thailand) and you 
1984  * use this factory method to construct a new date without specifying the
1985  * type, it will automatically give you back an instance of 
1986  * {@link ilib.Date.ThaiSolarDate}. This is convenient because you do not 
1987  * need to know which locales use which types of dates. In fact, you 
1988  * should always use this factory method to make new date instances unless
1989  * you know that you specifically need a date in a particular calendar.<p>
1990  * 
1991  * Also note that when you pass in the date components such as year, month,
1992  * day, etc., these components should be appropriate for the given date
1993  * being instantiated. That is, in our Thai example in the previous
1994  * paragraph, the year and such should be given as a Thai solar year, not
1995  * the Gregorian year that you get from the Javascript Date class. In
1996  * order to initialize a date instance when you don't know what subclass
1997  * will be instantiated for the locale, use a parameter such as "unixtime" 
1998  * or "julianday" which are unambiguous and based on UTC time, instead of
1999  * the year/month/date date components. The date components for that UTC 
2000  * time will be calculated and the time zone offset will be automatically 
2001  * factored in.
2002  *  
2003  * @param {Object=} options options controlling the construction of this instance, or
2004  * undefined to use the default options
2005  * @return {ilib.Date} an instance of a calendar object of the appropriate type 
2006  */
2007 ilib.Date.newInstance = function(options) {
2008 	var locale = options && options.locale,
2009 		type = options && (options.type || options.calendar),
2010 		cons;
2011 
2012 	if (!locale) {
2013 		locale = new ilib.Locale();	// default locale
2014 	}
2015 	
2016 	if (!type) {
2017 		var info = new ilib.LocaleInfo(locale);
2018 		type = info.getCalendar();
2019 	}
2020 
2021 	cons = ilib.Date._constructors[type];
2022 	
2023 	// pass the same options through to the constructor so the subclass
2024 	// has the ability to do something with if it needs to
2025 	return cons && new cons(options);
2026 };
2027 
2028 /**
2029  * Convert JavaScript Date objects and other types into native ilib Dates. This accepts any
2030  * string or number that can be translated by the JavaScript Date class,
2031  * (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse)
2032  * any JavaScript Date classed object, any ilib.Date subclass, an ilib.JulianDay object, an object
2033  * containing the normal options to initialize an ilib.Date instance, or null (will 
2034  * return null or undefined if input is null or undefined). Normal output is 
2035  * a standard native subclass of the ilib Date object as appropriate for the locale.
2036  * 
2037  * @static
2038  * @private
2039  * @param  {ilib.Date|Object|ilib.JulianDay|Date|string|number=} inDate The input date object, string or Number.
2040  * @param  {ilib.String|string=} timezone timezone to use if a new date object is created
2041  * @return {ilib.Date|null|undefined} an ilib.Date subclass equivalent to the given inDate
2042  */
2043 ilib.Date._dateToIlib = function(inDate, timezone) {
2044 	if (typeof(inDate) === 'undefined' || inDate === null) {
2045 		return inDate;
2046 	}
2047 	if (inDate instanceof ilib.Date) {
2048 		return inDate;
2049 	}
2050 	if (inDate instanceof Date) {
2051 		return ilib.Date.newInstance({
2052 			unixtime: inDate.getTime(),
2053 			timezone: timezone
2054 		});
2055 	}
2056 	if (inDate instanceof ilib.JulianDay) {
2057 		return ilib.Date.newInstance({
2058 			jd: inDate,
2059 			timezone: timezone
2060 		});
2061 	}
2062 	if (typeof(inDate) === 'number') {
2063 		return ilib.Date.newInstance({
2064 			unixtime: inDate,
2065 			timezone: timezone
2066 		});
2067 	}
2068 	if (typeof(inDate) === 'object') {
2069 		return ilib.Date.newInstance(inDate);
2070 	}
2071 	if (typeof(inDate) === 'string') {
2072 		inDate = new Date(inDate);
2073 	}
2074 	return ilib.Date.newInstance({
2075 		unixtime: inDate.getTime(),
2076 		timezone: timezone
2077 	});
2078 };
2079 
2080 /* place for the subclasses to put their constructors so that the factory method
2081  * can find them. Do this to add your date after it's defined: 
2082  * ilib.Date._constructors["mytype"] = ilib.Date.MyTypeConstructor;
2083  */
2084 ilib.Date._constructors = {};
2085 
2086 ilib.Date.prototype = {
2087 	getType: function() {
2088 		return "ilib.Date";
2089 	},
2090 	
2091 	/**
2092 	 * Return the unix time equivalent to this date instance. Unix time is
2093 	 * the number of milliseconds since midnight on Jan 1, 1970 UTC (Gregorian). This 
2094 	 * method only returns a valid number for dates between midnight, 
2095 	 * Jan 1, 1970 UTC (Gregorian) and Jan 19, 2038 at 3:14:07am UTC (Gregorian) when 
2096 	 * the unix time runs out. If this instance encodes a date outside of that range, 
2097 	 * this method will return -1. For date types that are not Gregorian, the point 
2098 	 * in time represented by this date object will only give a return value if it
2099 	 * is in the correct range in the Gregorian calendar as given previously.
2100 	 * 
2101 	 * @return {number} a number giving the unix time, or -1 if the date is outside the
2102 	 * valid unix time range
2103 	 */
2104 	getTime: function() {
2105 		return this.rd.getTime(); 
2106 	},
2107 	
2108 	/**
2109 	 * Return the extended unix time equivalent to this Gregorian date instance. Unix time is
2110 	 * the number of milliseconds since midnight on Jan 1, 1970 UTC. Traditionally unix time
2111 	 * (or the type "time_t" in C/C++) is only encoded with an unsigned 32 bit integer, and thus 
2112 	 * runs out on Jan 19, 2038. However, most Javascript engines encode numbers well above 
2113 	 * 32 bits and the Date object allows you to encode up to 100 million days worth of time 
2114 	 * after Jan 1, 1970, and even more interestingly, 100 million days worth of time before
2115 	 * Jan 1, 1970 as well. This method returns the number of milliseconds in that extended 
2116 	 * range. If this instance encodes a date outside of that range, this method will return
2117 	 * NaN.
2118 	 * 
2119 	 * @return {number} a number giving the extended unix time, or Nan if the date is outside 
2120 	 * the valid extended unix time range
2121 	 */
2122 	getTimeExtended: function() {
2123 		return this.rd.getTimeExtended();
2124 	},
2125 
2126 	/**
2127 	 * Set the time of this instance according to the given unix time. Unix time is
2128 	 * the number of milliseconds since midnight on Jan 1, 1970.
2129 	 * 
2130 	 * @param {number} millis the unix time to set this date to in milliseconds 
2131 	 */
2132 	setTime: function(millis) {
2133 		this.rd = this.newRd({
2134 			unixtime: millis,
2135 			cal: this.cal
2136 		});
2137 		this._calcDateComponents();
2138 	},
2139 	
2140 	getDays: function() {
2141 		return this.day;
2142 	},
2143 	getMonths: function() {
2144 		return this.month;
2145 	},
2146 	getYears: function() {
2147 		return this.year;
2148 	},
2149 	getHours: function() {
2150 		return this.hour;
2151 	},
2152 	getMinutes: function() {
2153 		return this.minute;
2154 	},
2155 	getSeconds: function() {
2156 		return this.second;
2157 	},
2158 	getMilliseconds: function() {
2159 		return this.millisecond;
2160 	},
2161 
2162 	setDays: function(day) {
2163 		this.day = parseInt(day, 10) || 1;
2164 		this.rd._setDateComponents(this);
2165 	},
2166 	setMonths: function(month) {
2167 		this.month = parseInt(month, 10) || 1;
2168 		this.rd._setDateComponents(this);
2169 	},
2170 	setYears: function(year) {
2171 		this.year = parseInt(year, 10) || 0;
2172 		this.rd._setDateComponents(this);
2173 	},
2174 	
2175 	setHours: function(hour) {
2176 		this.hour = parseInt(hour, 10) || 0;
2177 		this.rd._setDateComponents(this);
2178 	},
2179 	setMinutes: function(minute) {
2180 		this.minute = parseInt(minute, 10) || 0;
2181 		this.rd._setDateComponents(this);
2182 	},
2183 	setSeconds: function(second) {
2184 		this.second = parseInt(second, 10) || 0;
2185 		this.rd._setDateComponents(this);
2186 	},
2187 	setMilliseconds: function(milli) {
2188 		this.millisecond = parseInt(milli, 10) || 0;
2189 		this.rd._setDateComponents(this);
2190 	},
2191 	
2192 	/**
2193 	 * Return a new date instance in the current calendar that represents the first instance 
2194 	 * of the given day of the week before the current date. The day of the week is encoded
2195 	 * as a number where 0 = Sunday, 1 = Monday, etc.
2196 	 * 
2197 	 * @param {number} dow the day of the week before the current date that is being sought
2198 	 * @return {ilib.Date} the date being sought
2199 	 */
2200 	before: function (dow) {
2201 		return this.cal.newDateInstance({
2202 			rd: this.rd.before(dow, this.offset),
2203 			timezone: this.timezone
2204 		});
2205 	},
2206 	
2207 	/**
2208 	 * Return a new date instance in the current calendar that represents the first instance 
2209 	 * of the given day of the week after the current date. The day of the week is encoded
2210 	 * as a number where 0 = Sunday, 1 = Monday, etc.
2211 	 * 
2212 	 * @param {number} dow the day of the week after the current date that is being sought
2213 	 * @return {ilib.Date} the date being sought
2214 	 */
2215 	after: function (dow) {
2216 		return this.cal.newDateInstance({
2217 			rd: this.rd.after(dow, this.offset),
2218 			timezone: this.timezone
2219 		});
2220 	},
2221 
2222 	/**
2223 	 * Return a new Gregorian date instance that represents the first instance of the 
2224 	 * given day of the week on or before the current date. The day of the week is encoded
2225 	 * as a number where 0 = Sunday, 1 = Monday, etc.
2226 	 * 
2227 	 * @param {number} dow the day of the week on or before the current date that is being sought
2228 	 * @return {ilib.Date} the date being sought
2229 	 */
2230 	onOrBefore: function (dow) {
2231 		return this.cal.newDateInstance({
2232 			rd: this.rd.onOrBefore(dow, this.offset),
2233 			timezone: this.timezone
2234 		});
2235 	},
2236 
2237 	/**
2238 	 * Return a new Gregorian date instance that represents the first instance of the 
2239 	 * given day of the week on or after the current date. The day of the week is encoded
2240 	 * as a number where 0 = Sunday, 1 = Monday, etc.
2241 	 * 
2242 	 * @param {number} dow the day of the week on or after the current date that is being sought
2243 	 * @return {ilib.Date} the date being sought
2244 	 */
2245 	onOrAfter: function (dow) {
2246 		return this.cal.newDateInstance({
2247 			rd: this.rd.onOrAfter(dow, this.offset),
2248 			timezone: this.timezone
2249 		});
2250 	},
2251 	
2252 	/**
2253 	 * Return a Javascript Date object that is equivalent to this date
2254 	 * object.
2255 	 * 
2256 	 * @return {Date|undefined} a javascript Date object
2257 	 */
2258 	getJSDate: function() {
2259 		var unix = this.rd.getTimeExtended();
2260 		return isNaN(unix) ? undefined : new Date(unix); 
2261 	},
2262 	
2263 	/**
2264 	 * Return the Rata Die (fixed day) number of this date.
2265 	 * 
2266 	 * @protected
2267 	 * @return {number} the rd date as a number
2268 	 */
2269 	getRataDie: function() {
2270 		return this.rd.getRataDie();
2271 	},
2272 	
2273 	/**
2274 	 * Set the date components of this instance based on the given rd.
2275 	 * @protected
2276 	 * @param {number} rd the rata die date to set
2277 	 */
2278 	setRd: function (rd) {
2279 		this.rd = this.newRd({
2280 			rd: rd,
2281 			cal: this.cal
2282 		});
2283 		this._calcDateComponents();
2284 	},
2285 	
2286 	/**
2287 	 * Return the Julian Day equivalent to this calendar date as a number.
2288 	 * 
2289 	 * @return {number} the julian date equivalent of this date
2290 	 */
2291 	getJulianDay: function() {
2292 		return this.rd.getJulianDay();
2293 	},
2294 	
2295 	/**
2296 	 * Set the date of this instance using a Julian Day.
2297 	 * @param {number|ilib.JulianDay} date the Julian Day to use to set this date
2298 	 */
2299 	setJulianDay: function (date) {
2300 		this.rd = this.newRd({
2301 			julianday: (typeof(date) === 'object') ? date.getDate() : date,
2302 			cal: this.cal
2303 		});
2304 		this._calcDateComponents();
2305 	},
2306 
2307 	/**
2308 	 * Return the time zone associated with this date, or 
2309 	 * undefined if none was specified in the constructor.
2310 	 * 
2311 	 * @return {string|undefined} the name of the time zone for this date instance
2312 	 */
2313 	getTimeZone: function() {
2314 		return this.timezone || "local";
2315 	},
2316 	
2317 	/**
2318 	 * Set the time zone associated with this date.
2319 	 * @param {string=} tzName the name of the time zone to set into this date instance,
2320 	 * or "undefined" to unset the time zone 
2321 	 */
2322 	setTimeZone: function (tzName) {
2323 		if (!tzName || tzName === "") {
2324 			// same as undefining it
2325 			this.timezone = undefined;
2326 			this.tz = undefined;
2327 		} else if (typeof(tzName) === 'string') {
2328 			this.timezone = tzName;
2329 			this.tz = undefined;
2330 			// assuming the same UTC time, but a new time zone, now we have to 
2331 			// recalculate what the date components are
2332 			this._calcDateComponents();
2333 		}
2334 	},
2335 	
2336 	/**
2337 	 * Return the rd number of the first Sunday of the given ISO year.
2338 	 * @protected
2339 	 * @param {number} year the year for which the first Sunday is being sought
2340 	 * @return {number} the rd of the first Sunday of the ISO year
2341 	 */
2342 	firstSunday: function (year) {
2343 		var firstDay = this.newRd({
2344 			year: year,
2345 			month: 1,
2346 			day: 1,
2347 			hour: 0,
2348 			minute: 0,
2349 			second: 0,
2350 			millisecond: 0,
2351 			cal: this.cal
2352 		});
2353 		var firstThu = this.newRd({
2354 			rd: firstDay.onOrAfter(4),
2355 			cal: this.cal
2356 		});
2357 		return firstThu.before(0);
2358 	},
2359 	
2360 	/**
2361 	 * Return the ISO 8601 week number in the current year for the current date. The week
2362 	 * number ranges from 0 to 55, as some years have 55 weeks assigned to them in some
2363 	 * calendars.
2364 	 * 
2365 	 * @return {number} the week number for the current date
2366 	 */
2367 	getWeekOfYear: function() {
2368 		var rd = Math.floor(this.rd.getRataDie());
2369 		var year = this._calcYear(rd + this.offset);
2370 		var yearStart = this.firstSunday(year);
2371 		var nextYear;
2372 		
2373 		// if we have a January date, it may be in this ISO year or the previous year
2374 		if (rd < yearStart) {
2375 			yearStart = this.firstSunday(year-1);
2376 		} else {
2377 			// if we have a late December date, it may be in this ISO year, or the next year
2378 			nextYear = this.firstSunday(year+1);
2379 			if (rd >= nextYear) {
2380 				yearStart = nextYear;
2381 			}
2382 		}
2383 		
2384 		return Math.floor((rd-yearStart)/7) + 1;
2385 	},
2386 	
2387 	/**
2388 	 * Return the ordinal number of the week within the month. The first week of a month is
2389 	 * the first one that contains 4 or more days in that month. If any days precede this
2390 	 * first week, they are marked as being in week 0. This function returns values from 0
2391 	 * through 6.<p>
2392 	 * 
2393 	 * The locale is a required parameter because different locales that use the same 
2394 	 * Gregorian calendar consider different days of the week to be the beginning of
2395 	 * the week. This can affect the week of the month in which some days are located.
2396 	 * 
2397 	 * @param {ilib.Locale|string} locale the locale or locale spec to use when figuring out 
2398 	 * the first day of the week
2399 	 * @return {number} the ordinal number of the week within the current month
2400 	 */
2401 	getWeekOfMonth: function(locale) {
2402 		var li = new ilib.LocaleInfo(locale);
2403 		
2404 		var first = this.newRd({
2405 			year: this._calcYear(this.rd.getRataDie()+this.offset),
2406 			month: this.getMonths(),
2407 			day: 1,
2408 			hour: 0,
2409 			minute: 0,
2410 			second: 0,
2411 			millisecond: 0,
2412 			cal: this.cal
2413 		});
2414 		var weekStart = first.onOrAfter(li.getFirstDayOfWeek());
2415 		
2416 		if (weekStart - first.getRataDie() > 3) {
2417 			// if the first week has 4 or more days in it of the current month, then consider
2418 			// that week 1. Otherwise, it is week 0. To make it week 1, move the week start
2419 			// one week earlier.
2420 			weekStart -= 7;
2421 		}
2422 		return Math.floor((this.rd.getRataDie() - weekStart) / 7) + 1;
2423 	}
2424 };
2425 
2426 /*
2427  * util/utils.js - Core utility routines
2428  * 
2429  * Copyright © 2012-2014, JEDLSoft
2430  *
2431  * Licensed under the Apache License, Version 2.0 (the "License");
2432  * you may not use this file except in compliance with the License.
2433  * You may obtain a copy of the License at
2434  *
2435  *     http://www.apache.org/licenses/LICENSE-2.0
2436  *
2437  * Unless required by applicable law or agreed to in writing, software
2438  * distributed under the License is distributed on an "AS IS" BASIS,
2439  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2440  *
2441  * See the License for the specific language governing permissions and
2442  * limitations under the License.
2443  */
2444 
2445 // !depends ilibglobal.js
2446 
2447 /**
2448  * If Function.prototype.bind does not exist in this JS engine, this
2449  * function reimplements it in terms of older JS functions.
2450  * bind() doesn't exist in many older browsers.
2451  * 
2452  * @param {Object} scope object that the method should operate on
2453  * @param {function(...)} method method to call
2454  * @return {function(...)|undefined} function that calls the given method 
2455  * in the given scope with all of its arguments properly attached, or
2456  * undefined if there was a problem with the arguments
2457  */
2458 ilib.bind = function(scope, method/*, bound arguments*/){
2459 	if (!scope || !method) {
2460 		return undefined;
2461 	}
2462 	
2463 	/** @protected 
2464 	 * @param {Arguments} inArrayLike
2465 	 * @param {number=} inOffset
2466 	 */
2467 	function cloneArray(inArrayLike, inOffset) {
2468 		var arr = [];
2469 		for(var i = inOffset || 0, l = inArrayLike.length; i<l; i++){
2470 			arr.push(inArrayLike[i]);
2471 		}
2472 		return arr;
2473 	}
2474 
2475 	if (typeof(method) === 'function') {
2476 		var func, args = cloneArray(arguments, 2);
2477 		if (typeof(method.bind) === 'function') {
2478 			func = method.bind.apply(method, [scope].concat(args));
2479 		} else {
2480 			func = function() {
2481 				var nargs = cloneArray(arguments);
2482 				// invoke with collected args
2483 				return method.apply(scope, args.concat(nargs));
2484 			};
2485 		}
2486 		return func;
2487 	}
2488 	return undefined;
2489 };
2490 
2491 /**
2492  * Merge the properties of object2 into object1 in a deep manner and return a merged
2493  * object. If the property exists in both objects, the value in object2 will overwrite 
2494  * the value in object1. If a property exists in object1, but not in object2, its value
2495  * will not be touched. If a property exists in object2, but not in object1, it will be 
2496  * added to the merged result.<p>
2497  * 
2498  * Name1 and name2 are for creating debug output only. They are not necessary.<p>
2499  * 
2500  * Depends directive: !depends utils.js
2501  * 
2502  * @param {*} object1 the object to merge into
2503  * @param {*} object2 the object to merge
2504  * @param {boolean=} replace if true, replace the array elements in object1 with those in object2.
2505  * If false, concatenate array elements in object1 with items in object2.
2506  * @param {string=} name1 name of the object being merged into
2507  * @param {string=} name2 name of the object being merged in
2508  * @return {Object} the merged object
2509  */
2510 ilib.merge = function (object1, object2, replace, name1, name2) {
2511 	var prop = undefined,
2512 		newObj = {};
2513 	for (prop in object1) {
2514 		if (prop && typeof(object1[prop]) !== 'undefined') {
2515 			newObj[prop] = object1[prop];
2516 		}
2517 	}
2518 	for (prop in object2) {
2519 		if (prop && typeof(object2[prop]) !== 'undefined') {
2520 			if (object1[prop] instanceof Array && object2[prop] instanceof Array) {
2521 				if (typeof(replace) !== 'boolean' || !replace) {
2522 					newObj[prop] = new Array();
2523 					newObj[prop] = newObj[prop].concat(object1[prop]);
2524 					newObj[prop] = newObj[prop].concat(object2[prop]);
2525 				} else {
2526 					newObj[prop] = object2[prop];
2527 				}
2528 			} else if (typeof(object1[prop]) === 'object' && typeof(object2[prop]) === 'object') {
2529 				newObj[prop] = ilib.merge(object1[prop], object2[prop], replace);
2530 			} else {
2531 				// for debugging. Used to determine whether or not json files are overriding their parents unnecessarily
2532 				if (name1 && name2 && newObj[prop] == object2[prop]) {
2533 					console.log("Property " + prop + " in " + name1 + " is being overridden by the same value in " + name2);
2534 				}
2535 				newObj[prop] = object2[prop];
2536 			}
2537 		}
2538 	}
2539 	return newObj;
2540 };
2541 
2542 /**
2543  * Find and merge all the locale data for a particular prefix in the given locale
2544  * and return it as a single javascript object. This merges the data in the 
2545  * correct order:
2546  * 
2547  * <ol>
2548  * <li>shared data (usually English)
2549  * <li>data for language
2550  * <li>data for language + region
2551  * <li>data for language + region + script
2552  * <li>data for language + region + script + variant
2553  * </ol>
2554  * 
2555  * It is okay for any of the above to be missing. This function will just skip the 
2556  * missing data. However, if everything except the shared data is missing, this 
2557  * function returns undefined, allowing the caller to go and dynamically load the
2558  * data instead.
2559  *  
2560  * @param {string} prefix prefix under ilib.data of the data to merge
2561  * @param {ilib.Locale} locale locale of the data being sought
2562  * @param {boolean=} replaceArrays if true, replace the array elements in object1 with those in object2.
2563  * If false, concatenate array elements in object1 with items in object2.
2564  * @param {boolean=} returnOne if true, only return the most locale-specific data. If false,
2565  * merge all the relevant locale data together.
2566  * @return {Object?} the merged locale data
2567  */
2568 ilib.mergeLocData = function (prefix, locale, replaceArrays, returnOne) {
2569 	var data = undefined;
2570 	var loc = locale || new ilib.Locale();
2571 	var foundLocaleData = false;
2572 	var property = prefix;
2573 	var mostSpecific;
2574 
2575 	data = ilib.data[prefix] || {};
2576 
2577 	mostSpecific = data;
2578 
2579 	if (loc.getLanguage()) {
2580 		property = prefix + '_' + loc.getLanguage();
2581 		if (ilib.data[property]) {
2582 			foundLocaleData = true;
2583 			data = ilib.merge(data, ilib.data[property], replaceArrays);
2584 			mostSpecific = ilib.data[property];
2585 		}
2586 	}
2587 	
2588 	if (loc.getRegion()) {
2589 		property = prefix + '_' + loc.getRegion();
2590 		if (ilib.data[property]) {
2591 			foundLocaleData = true;
2592 			data = ilib.merge(data, ilib.data[property], replaceArrays);
2593 			mostSpecific = ilib.data[property];
2594 		}
2595 	}
2596 	
2597 	if (loc.getLanguage()) {
2598 		property = prefix + '_' + loc.getLanguage();
2599 		
2600 		if (loc.getScript()) {
2601 			property = prefix + '_' + loc.getLanguage() + '_' + loc.getScript();
2602 			if (ilib.data[property]) {
2603 				foundLocaleData = true;
2604 				data = ilib.merge(data, ilib.data[property], replaceArrays);
2605 				mostSpecific = ilib.data[property];
2606 			}
2607 		}
2608 		
2609 		if (loc.getRegion()) {
2610 			property = prefix + '_' + loc.getLanguage() + '_' + loc.getRegion();
2611 			if (ilib.data[property]) {
2612 				foundLocaleData = true;
2613 				data = ilib.merge(data, ilib.data[property], replaceArrays);
2614 				mostSpecific = ilib.data[property];
2615 			}
2616 		}		
2617 	}
2618 	
2619 	if (loc.getRegion() && loc.getVariant()) {
2620 		property = prefix + '_' + loc.getLanguage() + '_' + loc.getVariant();
2621 		if (ilib.data[property]) {
2622 			foundLocaleData = true;
2623 			data = ilib.merge(data, ilib.data[property], replaceArrays);
2624 			mostSpecific = ilib.data[property];
2625 		}
2626 	}
2627 
2628 	if (loc.getLanguage() && loc.getScript() && loc.getRegion()) {
2629 		property = prefix + '_' + loc.getLanguage() + '_' + loc.getScript() + '_' + loc.getRegion();
2630 		if (ilib.data[property]) {
2631 			foundLocaleData = true;
2632 			data = ilib.merge(data, ilib.data[property], replaceArrays);
2633 			mostSpecific = ilib.data[property];
2634 		}
2635 	}
2636 
2637 	if (loc.getLanguage() && loc.getRegion() && loc.getVariant()) {
2638 		property = prefix + '_' + loc.getLanguage() + '_' + loc.getRegion() + '_' + loc.getVariant();
2639 		if (ilib.data[property]) {
2640 			foundLocaleData = true;
2641 			data = ilib.merge(data, ilib.data[property], replaceArrays);
2642 			mostSpecific = ilib.data[property];
2643 		}
2644 	}
2645 
2646 	if (loc.getLanguage() && loc.getScript() && loc.getRegion() && loc.getVariant()) {
2647 		property = prefix + '_' + loc.getLanguage() + '_' + loc.getScript() + '_' + loc.getRegion() + '_' + loc.getVariant();
2648 		if (ilib.data[property]) {
2649 			foundLocaleData = true;
2650 			data = ilib.merge(data, ilib.data[property], replaceArrays);
2651 			mostSpecific = ilib.data[property];
2652 		}
2653 	}
2654 	
2655 	return foundLocaleData ? (returnOne ? mostSpecific : data) : undefined;
2656 };
2657 
2658 /**
2659  * Return an array of relative path names for the
2660  * files that represent the data for the given locale.<p>
2661  * 
2662  * Note that to prevent the situation where a directory for
2663  * a language exists next to the directory for a region where
2664  * the language code and region code differ only by case, the 
2665  * plain region directories are located under the special 
2666  * "undefined" language directory which has the ISO code "und".
2667  * The reason is that some platforms have case-insensitive 
2668  * file systems, and you cannot have 2 directories with the 
2669  * same name which only differ by case. For example, "es" is
2670  * the ISO 639 code for the language "Spanish" and "ES" is
2671  * the ISO 3166 code for the region "Spain", so both the
2672  * directories cannot exist underneath "locale". The region
2673  * therefore will be loaded from "und/ES" instead.<p>  
2674  * 
2675  * <h4>Variations</h4>
2676  * 
2677  * With only language and region specified, the following
2678  * sequence of paths will be generated:<p>
2679  * 
2680  * <pre>
2681  * language
2682  * und/region
2683  * language/region
2684  * </pre>
2685  * 
2686  * With only language and script specified:<p>
2687  * 
2688  * <pre>
2689  * language
2690  * language/script
2691  * </pre>
2692  * 
2693  * With only script and region specified:<p>
2694  * 
2695  * <pre>
2696  * und/region  
2697  * </pre>
2698  * 
2699  * With only region and variant specified:<p>
2700  * 
2701  * <pre>
2702  * und/region
2703  * region/variant
2704  * </pre>
2705  * 
2706  * With only language, script, and region specified:<p>
2707  * 
2708  * <pre>
2709  * language
2710  * und/region
2711  * language/script
2712  * language/region
2713  * language/script/region
2714  * </pre>
2715  * 
2716  * With only language, region, and variant specified:<p>
2717  * 
2718  * <pre>
2719  * language
2720  * und/region
2721  * language/region
2722  * region/variant
2723  * language/region/variant
2724  * </pre>
2725  * 
2726  * With all parts specified:<p>
2727  * 
2728  * <pre>
2729  * language
2730  * und/region
2731  * language/script
2732  * language/region
2733  * region/variant
2734  * language/script/region
2735  * language/region/variant
2736  * language/script/region/variant
2737  * </pre>
2738  * 
2739  * @param {ilib.Locale} locale load the files for this locale
2740  * @param {string?} name the file name of each file to load without
2741  * any path
2742  * @return {Array.<string>} An array of relative path names
2743  * for the files that contain the locale data
2744  */
2745 ilib.getLocFiles = function(locale, name) {
2746 	var dir = "";
2747 	var files = [];
2748 	var filename = name || "resources.json";
2749 	var loc = locale || new ilib.Locale();
2750 	
2751 	var language = loc.getLanguage();
2752 	var region = loc.getRegion();
2753 	var script = loc.getScript();
2754 	var variant = loc.getVariant();
2755 	
2756 	files.push(filename); // generic shared file
2757 	
2758 	if (language) {
2759 		dir = language + "/";
2760 		files.push(dir + filename);
2761 	}
2762 	
2763 	if (region) {
2764 		dir = "und/" + region + "/";
2765 		files.push(dir + filename);
2766 	}
2767 	
2768 	if (language) {
2769 		if (script) {
2770 			dir = language + "/" + script + "/";
2771 			files.push(dir + filename);
2772 		}
2773 		if (region) {
2774 			dir = language + "/" + region + "/";
2775 			files.push(dir + filename);
2776 		}
2777 	}
2778 	
2779 	if (region && variant) {
2780 		dir = "und/" + region + "/" + variant + "/";
2781 		files.push(dir + filename);
2782 	}
2783 
2784 	if (language && script && region) {
2785 		dir = language + "/" + script + "/" + region + "/";
2786 		files.push(dir + filename);
2787 	}
2788 
2789 	if (language && region && variant) {
2790 		dir = language + "/" + region + "/" + variant + "/";
2791 		files.push(dir + filename);
2792 	}
2793 
2794 	if (language && script && region && variant) {
2795 		dir = language + "/" + script + "/" + region + "/" + variant + "/";
2796 		files.push(dir + filename);
2797 	}
2798 	
2799 	return files;
2800 };
2801 
2802 /**
2803  * Return true if the given object has no properties.<p>
2804  * 
2805  * Depends directive: !depends utils.js
2806  * 
2807  * @param {Object} obj the object to check
2808  * @return {boolean} true if the given object has no properties, false otherwise
2809  */
2810 ilib.isEmpty = function (obj) {
2811 	var prop = undefined;
2812 	
2813 	if (!obj) {
2814 		return true;
2815 	}
2816 	
2817 	for (prop in obj) {
2818 		if (prop && typeof(obj[prop]) !== 'undefined') {
2819 			return false;
2820 		}
2821 	}
2822 	return true;
2823 };
2824 
2825 
2826 /**
2827  * @private
2828  */
2829 ilib.hashCode = function(obj) {
2830 	var hash = 0;
2831 	
2832 	function addHash(hash, newValue) {
2833 		// co-prime numbers creates a nicely distributed hash
2834 		hash *= 65543;
2835 		hash += newValue;
2836 		hash %= 2147483647; 
2837 		return hash;
2838 	}
2839 	
2840 	function stringHash(str) {
2841 		var hash = 0;
2842 		for (var i = 0; i < str.length; i++) {
2843 			hash = addHash(hash, str.charCodeAt(i));
2844 		}
2845 		return hash;
2846 	}
2847 	
2848 	switch (typeof(obj)) {
2849 		case 'undefined':
2850 			hash = 0;
2851 			break;
2852 		case 'string':
2853 			hash = stringHash(obj);
2854 			break;
2855 		case 'function':
2856 		case 'number':
2857 		case 'xml':
2858 			hash = stringHash(String(obj));
2859 			break;
2860 		case 'boolean':
2861 			hash = obj ? 1 : 0;
2862 			break;
2863 		case 'object':
2864 			var props = [];
2865 			for (var p in obj) {
2866 				if (obj.hasOwnProperty(p)) {
2867 					props.push(p);
2868 				}
2869 			}
2870 			// make sure the order of the properties doesn't matter
2871 			props.sort();
2872 			for (var i = 0; i < props.length; i++) {
2873 				hash = addHash(hash, stringHash(props[i]));
2874 				hash = addHash(hash, ilib.hashCode(obj[props[i]]));
2875 			}
2876 			break;
2877 	}
2878 	
2879 	return hash;
2880 };
2881 
2882 
2883 /**
2884  * Load data using the new loader object or via the old function callback.
2885  * @private
2886  */
2887 ilib._callLoadData = function (files, sync, params, callback) {
2888 	// console.log("ilib._callLoadData called");
2889 	if (typeof(ilib._load) === 'function') {
2890 		// console.log("ilib._callLoadData: calling as a regular function");
2891 		return ilib._load(files, sync, params, callback);
2892 	} else if (typeof(ilib._load) === 'object' && ilib._load instanceof ilib.Loader) {
2893 		// console.log("ilib._callLoadData: calling as an object");
2894 		return ilib._load.loadFiles(files, sync, params, callback);
2895 	}
2896 	
2897 	// console.log("ilib._callLoadData: not calling. Type is " + typeof(ilib._load) + " and instanceof says " + (ilib._load instanceof ilib.Loader));
2898 	return undefined;
2899 };
2900 
2901 /**
2902  * Find locale data or load it in. If the data with the given name is preassembled, it will
2903  * find the data in ilib.data. If the data is not preassembled but there is a loader function,
2904  * this function will call it to load the data. Otherwise, the callback will be called with
2905  * undefined as the data. This function will create a cache under the given class object.
2906  * If data was successfully loaded, it will be set into the cache so that future access to 
2907  * the same data for the same locale is much quicker.<p>
2908  * 
2909  * The parameters can specify any of the following properties:<p>
2910  * 
2911  * <ul>
2912  * <li><i>name</i> - String. The name of the file being loaded. Default: resources.json
2913  * <li><i>object</i> - Object. The class attempting to load data. The cache is stored inside of here.
2914  * <li><i>locale</i> - ilib.Locale. The locale for which data is loaded. Default is the current locale.
2915  * <li><i>nonlocale</i> - boolean. If true, the data being loaded is not locale-specific.
2916  * <li><i>type</i> - String. Type of file to load. This can be "json" or "other" type. Default: "json" 
2917  * <li><i>replace</i> - boolean. When merging json objects, this parameter controls whether to merge arrays
2918  * or have arrays replace each other. If true, arrays in child objects replace the arrays in parent 
2919  * objects. When false, the arrays in child objects are concatenated with the arrays in parent objects.  
2920  * <li><i>loadParams</i> - Object. An object with parameters to pass to the loader function
2921  * <li><i>sync</i> - boolean. Whether or not to load the data synchronously
2922  * <li><i>callback</i> - function(?)=. callback Call back function to call when the data is available.
2923  * Data is not returned from this method, so a callback function is mandatory.
2924  * </ul>
2925  * 
2926  * @param {Object} params Parameters configuring how to load the files (see above)
2927  */
2928 ilib.loadData = function(params) {
2929 	var name = "resources.json",
2930 		object = undefined, 
2931 		locale = new ilib.Locale(ilib.getLocale()), 
2932 		sync = false, 
2933 		type = undefined,
2934 		loadParams = {},
2935 		callback = undefined,
2936 		nonlocale = false,
2937 		replace = false,
2938 		basename;
2939 	
2940 	if (!params || typeof(params.callback) !== 'function') {
2941 		return;
2942 	}
2943 
2944 	if (params.name) {
2945 		name = params.name;
2946 	}
2947 	if (params.object) {
2948 		object = params.object;
2949 	}
2950 	if (params.locale) {
2951 		locale = (typeof(params.locale) === 'string') ? new ilib.Locale(params.locale) : params.locale;
2952 	}			
2953 	if (params.type) {
2954 		type = params.type;
2955 	}
2956 	if (params.loadParams) {
2957 		loadParams = params.loadParams;
2958 	}
2959 	if (params.sync) {
2960 		sync = params.sync;
2961 	}
2962 	if (params.nonlocale) {
2963 		nonlocale = !!params.nonlocale;
2964 	}
2965 	if (typeof(params.replace) === 'boolean') {
2966 		replace = params.replace;
2967 	}
2968 	
2969 	callback = params.callback;
2970 	
2971 	if (object && !object.cache) {
2972 		object.cache = {};
2973 	}
2974 	
2975 	if (!type) {
2976 		var dot = name.lastIndexOf(".");
2977 		type = (dot !== -1) ? name.substring(dot+1) : "text";
2978 	}
2979 
2980 	var spec = ((!nonlocale && locale.getSpec().replace(/-/g, '_')) || "root") + "," + name + "," + String(ilib.hashCode(loadParams));
2981 	if (!object || typeof(object.cache[spec]) === 'undefined') {
2982 		var data, returnOne = (loadParams && loadParams.returnOne);
2983 		
2984 		if (type === "json") {
2985 			// console.log("type is json");
2986 			basename = name.substring(0, name.lastIndexOf("."));
2987 			if (nonlocale) {
2988 				basename = basename.replace(/\//g, '.').replace(/[\\\+\-]/g, "_");
2989 				data = ilib.data[basename];
2990 			} else {
2991 				data = ilib.mergeLocData(basename, locale, replace, returnOne);
2992 			}
2993 			if (data) {
2994 				// console.log("found assembled data");
2995 				if (object) {
2996 					object.cache[spec] = data;
2997 				}
2998 				callback(data);
2999 				return;
3000 			}
3001 		}
3002 		
3003 		// console.log("ilib._load is " + typeof(ilib._load));
3004 		if (typeof(ilib._load) !== 'undefined') {
3005 			// the data is not preassembled, so attempt to load it dynamically
3006 			var files = nonlocale ? [ name || "resources.json" ] : ilib.getLocFiles(locale, name);
3007 			if (type !== "json") {
3008 				loadParams.returnOne = true;
3009 			}
3010 			
3011 			ilib._callLoadData(files, sync, loadParams, ilib.bind(this, function(arr) {
3012 				if (type === "json") {
3013 					data = ilib.data[basename] || {};
3014 					for (var i = 0; i < arr.length; i++) {
3015 						if (typeof(arr[i]) !== 'undefined') {
3016 							data = loadParams.returnOne ? arr[i] : ilib.merge(data, arr[i], replace);
3017 						}
3018 					}
3019 					
3020 					if (object) {
3021 						object.cache[spec] = data;
3022 					}
3023 					callback(data);
3024 				} else {
3025 					var i = arr.length-1; 
3026 					while (i > -1 && !arr[i]) {
3027 						i--;
3028 					}
3029 					if (i > -1) {
3030 						if (object) {
3031 							object.cache[spec] = arr[i];
3032 						}
3033 						callback(arr[i]);
3034 					} else {
3035 						callback(undefined);
3036 					}
3037 				}
3038 			}));
3039 		} else {
3040 			// no data other than the generic shared data
3041 			if (type === "json") {
3042 				data = ilib.data[basename];
3043 			}
3044 			if (object && data) {
3045 				object.cache[spec] = data;
3046 			}
3047 			callback(data);
3048 		}
3049 	} else {
3050 		callback(object.cache[spec]);
3051 	}
3052 };
3053 
3054 /*
3055  * util/math.js - Misc math utility routines
3056  * 
3057  * Copyright © 2013, JEDLSoft
3058  *
3059  * Licensed under the Apache License, Version 2.0 (the "License");
3060  * you may not use this file except in compliance with the License.
3061  * You may obtain a copy of the License at
3062  *
3063  *     http://www.apache.org/licenses/LICENSE-2.0
3064  *
3065  * Unless required by applicable law or agreed to in writing, software
3066  * distributed under the License is distributed on an "AS IS" BASIS,
3067  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3068  *
3069  * See the License for the specific language governing permissions and
3070  * limitations under the License.
3071  */
3072 
3073 // !depends ilibglobal.js
3074 
3075 /**
3076  * Return the sign of the given number. If the sign is negative, this function
3077  * returns -1. If the sign is positive or zero, this function returns 1.
3078  * @static
3079  * @param {number} num the number to test
3080  * @return {number} -1 if the number is negative, and 1 otherwise
3081  */
3082 ilib.signum = function (num) {
3083 	var n = num;
3084 	if (typeof(num) === 'string') {
3085 		n = parseInt(num, 10);
3086 	} else if (typeof(num) !== 'number') {
3087 		return 1;
3088 	}
3089 	return (n < 0) ? -1 : 1;
3090 };
3091 
3092 
3093 /**
3094  * @protected
3095  */
3096 ilib._roundFnc = {
3097 	/**
3098 	 * @static
3099 	 * @protected
3100 	 * @param {number} num number to round
3101 	 * @return {number} rounded number
3102 	 */
3103 	floor: function (num) {
3104 		return Math.floor(num);
3105 	},
3106 	
3107 	/**
3108 	 * @static
3109 	 * @protected
3110 	 * @param {number} num number to round
3111 	 * @return {number} rounded number
3112 	 */
3113 	ceiling: function (num) {
3114 		return Math.ceil(num);
3115 	},
3116 	
3117 	/**
3118 	 * @static
3119 	 * @protected
3120 	 * @param {number} num number to round
3121 	 * @return {number} rounded number
3122 	 */
3123 	down: function (num) {
3124 		return (num < 0) ? Math.ceil(num) : Math.floor(num);
3125 	},
3126 	
3127 	/**
3128 	 * @static
3129 	 * @protected
3130 	 * @param {number} num number to round
3131 	 * @return {number} rounded number
3132 	 */
3133 	up: function (num) {
3134 		return (num < 0) ? Math.floor(num) : Math.ceil(num);
3135 	},
3136 	
3137 	/**
3138 	 * @static
3139 	 * @protected
3140 	 * @param {number} num number to round
3141 	 * @return {number} rounded number
3142 	 */
3143 	halfup: function (num) {
3144 		return (num < 0) ? Math.ceil(num - 0.5) : Math.floor(num + 0.5);
3145 	},
3146 	
3147 	/**
3148 	 * @static
3149 	 * @protected
3150 	 * @param {number} num number to round
3151 	 * @return {number} rounded number
3152 	 */
3153 	halfdown: function (num) {
3154 		return (num < 0) ? Math.floor(num + 0.5) : Math.ceil(num - 0.5);
3155 	},
3156 	
3157 	/**
3158 	 * @static
3159 	 * @protected
3160 	 * @param {number} num number to round
3161 	 * @return {number} rounded number
3162 	 */
3163 	halfeven: function (num) {
3164 		return (Math.floor(num) % 2 === 0) ? Math.ceil(num - 0.5) : Math.floor(num + 0.5);
3165 	},
3166 	
3167 	/**
3168 	 * @static
3169 	 * @protected
3170 	 * @param {number} num number to round
3171 	 * @return {number} rounded number
3172 	 */
3173 	halfodd: function (num) {
3174 		return (Math.floor(num) % 2 !== 0) ? Math.ceil(num - 0.5) : Math.floor(num + 0.5);
3175 	}
3176 };
3177 
3178 /**
3179  * Do a proper modulo function. The Javascript % operator will give the truncated
3180  * division algorithm, but for calendrical calculations, we need the Euclidean
3181  * division algorithm where the remainder of any division, whether the dividend
3182  * is negative or not, is always a positive number in the range [0, modulus).<p>
3183  * 
3184  * Depends directive: !depends utils.js
3185  * 
3186  * @param {number} dividend the number being divided
3187  * @param {number} modulus the number dividing the dividend. This should always be a positive number.
3188  * @return the remainder of dividing the dividend by the modulus.  
3189  */
3190 ilib.mod = function (dividend, modulus) {
3191 	if (modulus == 0) {
3192 		return 0;
3193 	}
3194 	var x = dividend % modulus;
3195 	return (x < 0) ? x + modulus : x;
3196 };
3197 
3198 /**
3199  * Do a proper adjusted modulo function. The Javascript % operator will give the truncated
3200  * division algorithm, but for calendrical calculations, we need the Euclidean
3201  * division algorithm where the remainder of any division, whether the dividend
3202  * is negative or not, is always a positive number in the range (0, modulus]. The adjusted
3203  * modulo function differs from the regular modulo function in that when the remainder is
3204  * zero, the modulus should be returned instead.<p>
3205  * 
3206  * Depends directive: !depends utils.js
3207  * 
3208  * @param {number} dividend the number being divided
3209  * @param {number} modulus the number dividing the dividend. This should always be a positive number.
3210  * @return the remainder of dividing the dividend by the modulus.  
3211  */
3212 ilib.amod = function (dividend, modulus) {
3213 	if (modulus == 0) {
3214 		return 0;
3215 	}
3216 	var x = dividend % modulus;
3217 	return (x <= 0) ? x + modulus : x;
3218 };
3219 
3220 /*
3221  * strings.js - ilib string subclass definition
3222  * 
3223  * Copyright © 2012-2014, JEDLSoft
3224  *
3225  * Licensed under the Apache License, Version 2.0 (the "License");
3226  * you may not use this file except in compliance with the License.
3227  * You may obtain a copy of the License at
3228  *
3229  *     http://www.apache.org/licenses/LICENSE-2.0
3230  *
3231  * Unless required by applicable law or agreed to in writing, software
3232  * distributed under the License is distributed on an "AS IS" BASIS,
3233  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3234  *
3235  * See the License for the specific language governing permissions and
3236  * limitations under the License.
3237  */
3238 
3239 // !depends ilibglobal.js util/utils.js locale.js util/math.js
3240 
3241 // !data plurals
3242 
3243 /**
3244  * @class
3245  * Create a new string instance. This string inherits from the Javascript
3246  * String class, and adds two more methods, fmt and fmtChoice. It can be
3247  * used anywhere that a normal Javascript string is used. The formatting
3248  * methods are of course most useful when localizing strings in an app
3249  * or web site in combination with the ilib.ResBundle class.<p>
3250  * 
3251  * Depends directive: !depends strings.js
3252  * 
3253  * @constructor
3254  * @param {string|ilib.String=} string initialize this instance with this string 
3255  */
3256 ilib.String = function (string) {
3257 	if (typeof(string) === 'object') {
3258 		if (string instanceof ilib.String) {
3259 			this.str = string.str;	
3260 		} else {
3261 			this.str = string.toString();
3262 		}
3263 	} else if (typeof(string) === 'string') {
3264 		this.str = new String(string);
3265 	} else {
3266 		this.str = "";
3267 	}
3268 	this.length = this.str.length;
3269 	this.cpLength = -1;
3270 	this.localeSpec = ilib.getLocale();
3271 };
3272 
3273 /**
3274  * Return true if the given character is a Unicode surrogate character,
3275  * either high or low.
3276  * 
3277  * @private
3278  * @static
3279  * @param {string} ch character to check
3280  * @return {boolean} true if the character is a surrogate
3281  */
3282 ilib.String._isSurrogate = function (ch) {
3283 	var n = ch.charCodeAt(0);
3284 	return ((n >= 0xDC00 && n <= 0xDFFF) || (n >= 0xD800 && n <= 0xDBFF));
3285 };
3286 
3287 /**
3288  * Convert a UCS-4 code point to a Javascript string. The codepoint can be any valid 
3289  * UCS-4 Unicode character, including supplementary characters. Standard Javascript
3290  * only supports supplementary characters using the UTF-16 encoding, which has 
3291  * values in the range 0x0000-0xFFFF. String.fromCharCode() will only
3292  * give you a string containing 16-bit characters, and will not properly convert 
3293  * the code point for a supplementary character (which has a value > 0xFFFF) into 
3294  * two UTF-16 surrogate characters. Instead, it will just just give you whatever
3295  * single character happens to be the same as your code point modulo 0x10000, which
3296  * is almost never what you want.<p> 
3297  * 
3298  * Similarly, that means if you use String.charCodeAt()
3299  * you will only retrieve a 16-bit value, which may possibly be a single
3300  * surrogate character that is part of a surrogate pair representing a character
3301  * in the supplementary plane. It will not give you a code point. Use 
3302  * ilib.String.codePointAt() to access code points in a string, or use 
3303  * an iterator to walk through the code points in a string. 
3304  * 
3305  * @static
3306  * @param {number} codepoint UCS-4 code point to convert to a character
3307  * @return {string} a string containing the character represented by the codepoint
3308  */
3309 ilib.String.fromCodePoint = function (codepoint) {
3310 	if (codepoint < 0x10000) {
3311 		return String.fromCharCode(codepoint);
3312 	} else {
3313 		var high = Math.floor(codepoint / 0x10000) - 1;
3314 		var low = codepoint & 0xFFFF;
3315 		
3316 		return String.fromCharCode(0xD800 | ((high & 0x000F) << 6) |  ((low & 0xFC00) >> 10)) +
3317 			String.fromCharCode(0xDC00 | (low & 0x3FF));
3318 	}
3319 };
3320 
3321 /**
3322  * Convert the character or the surrogate pair at the given
3323  * index into the intrinsic Javascript string to a Unicode 
3324  * UCS-4 code point.
3325  * 
3326  * @param {string} str string to get the code point from
3327  * @param {number} index index into the string
3328  * @return {number} code point of the character at the
3329  * given index into the string
3330  */
3331 ilib.String.toCodePoint = function(str, index) {
3332 	if (!str || str.length === 0) {
3333 		return -1;
3334 	}
3335 	var code = -1, high = str.charCodeAt(index);
3336 	if (high >= 0xD800 && high <= 0xDBFF) {
3337 		if (str.length > index+1) {
3338 			var low = str.charCodeAt(index+1);
3339 			if (low >= 0xDC00 && low <= 0xDFFF) {
3340 				code = (((high & 0x3C0) >> 6) + 1) << 16 |
3341 					(((high & 0x3F) << 10) | (low & 0x3FF));
3342 			}
3343 		}
3344 	} else {
3345 		code = high;
3346 	}
3347 	
3348 	return code;
3349 };
3350 
3351 /**
3352  * Load the plural the definitions of plurals for the locale.
3353  * @param {boolean=} sync
3354  * @param {ilib.Locale|string=} locale
3355  * @param {Object=} loadParams
3356  * @param {function(*)=} onLoad
3357  */
3358 ilib.String.loadPlurals = function (sync, locale, loadParams, onLoad) {
3359 	var loc;
3360 	if (locale) {
3361 		loc = (typeof(locale) === 'string') ? new ilib.Locale(locale) : locale;
3362 	} else {
3363 		loc = new ilib.Locale(ilib.getLocale());
3364 	}
3365 	var spec = loc.getLanguage();
3366 	if (!ilib.data["plurals_" + spec]) {
3367 		ilib.loadData({
3368 			name: "plurals.json",
3369 			object: ilib.String,
3370 			locale: loc,
3371 			sync: sync,
3372 			loadParams: loadParams,
3373 			callback: /** @type function(Object=):undefined */ ilib.bind(this, /** @type function() */ function(plurals) {
3374 				if (!plurals) {
3375 					ilib.String.cache[spec] = {};
3376 				}
3377 				ilib.data["plurals_" + spec] = plurals || {};
3378 				if (onLoad && typeof(onLoad) === 'function') {
3379 					onLoad(ilib.data["plurals_" + spec]);
3380 				}
3381 			})
3382 		});
3383 	} else {
3384 		if (onLoad && typeof(onLoad) === 'function') {
3385 			onLoad(ilib.data["plurals_" + spec]);
3386 		}
3387 	}
3388 };
3389 
3390 /**
3391  * @private
3392  * @static
3393  */
3394 ilib.String._fncs = {
3395 	/**
3396 	 * @private
3397 	 * @param {Object} obj
3398 	 * @return {string|undefined}
3399 	 */
3400 	firstProp: function (obj) {
3401 		for (var p in obj) {
3402 			if (p && obj[p]) {
3403 				return p;
3404 			}
3405 		}
3406 		return undefined; // should never get here
3407 	},
3408 	
3409 	/**
3410 	 * @private
3411 	 * @param {Object} obj
3412 	 * @param {number} n
3413 	 * @return {?}
3414 	 */
3415 	getValue: function (obj, n) {
3416 		if (typeof(obj) === 'object') {
3417 			var subrule = ilib.String._fncs.firstProp(obj);
3418 			return ilib.String._fncs[subrule](obj[subrule], n);
3419 		} else if (typeof(obj) === 'string') {
3420 			return n;
3421 		} else {
3422 			return obj;
3423 		}
3424 	},
3425 	
3426 	/**
3427 	 * @private
3428 	 * @param {number} n
3429 	 * @param {Array.<number|Array.<number>>} range
3430 	 * @return {boolean}
3431 	 */
3432 	matchRangeContinuous: function(n, range) {
3433 		for (var num in range) {
3434 			if (typeof(num) !== 'undefined' && typeof(range[num]) !== 'undefined') {
3435 				var obj = /** @type {Object|null|undefined} */ range[num];
3436 				if (typeof(obj) === 'number') {
3437 					if (n === range[num]) {
3438 						return true;
3439 					}
3440 				} else if (Object.prototype.toString.call(obj) === '[object Array]') {
3441 					if (n >= obj[0] && n <= obj[1]) {
3442 						return true;
3443 					}
3444 				}
3445 			}
3446 		}
3447 		return false;
3448 	},
3449 
3450 	/**
3451 	 * @private
3452 	 * @param {number} n
3453 	 * @param {Array.<number|Array.<number>>} range
3454 	 * @return {boolean}
3455 	 */
3456 	matchRange: function(n, range) {
3457 		if (Math.floor(n) !== n) {
3458 			return false;
3459 		}
3460 		return ilib.String._fncs.matchRangeContinuous(n, range);
3461 	},
3462 	
3463 	/**
3464 	 * @private
3465 	 * @param {Object} rule
3466 	 * @param {number} n
3467 	 * @return {boolean}
3468 	 */
3469 	is: function(rule, n) {
3470 		var left = ilib.String._fncs.getValue(rule[0], n);
3471 		var right = ilib.String._fncs.getValue(rule[1], n);
3472 		return left == right;
3473 		// return ilib.String._fncs.getValue(rule[0]) == ilib.String._fncs.getValue(rule[1]);
3474 	},
3475 	
3476 	/**
3477 	 * @private
3478 	 * @param {Object} rule
3479 	 * @param {number} n
3480 	 * @return {boolean}
3481 	 */
3482 	isnot: function(rule, n) {
3483 		return ilib.String._fncs.getValue(rule[0], n) != ilib.String._fncs.getValue(rule[1], n);
3484 	},
3485 	
3486 	/**
3487 	 * @private
3488 	 * @param {Object} rule
3489 	 * @param {number} n
3490 	 * @return {boolean}
3491 	 */
3492 	inrange: function(rule, n) {
3493 		return ilib.String._fncs.matchRange(ilib.String._fncs.getValue(rule[0], n), rule[1]);
3494 	},
3495 	
3496 	/**
3497 	 * @private
3498 	 * @param {Object} rule
3499 	 * @param {number} n
3500 	 * @return {boolean}
3501 	 */
3502 	notin: function(rule, n) {
3503 		return !ilib.String._fncs.matchRange(ilib.String._fncs.getValue(rule[0], n), rule[1]);
3504 	},
3505 	
3506 	/**
3507 	 * @private
3508 	 * @param {Object} rule
3509 	 * @param {number} n
3510 	 * @return {boolean}
3511 	 */
3512 	within: function(rule, n) {
3513 		return ilib.String._fncs.matchRangeContinuous(ilib.String._fncs.getValue(rule[0], n), rule[1]);		
3514 	},
3515 	
3516 	/**
3517 	 * @private
3518 	 * @param {Object} rule
3519 	 * @param {number} n
3520 	 * @return {number}
3521 	 */
3522 	mod: function(rule, n) {
3523 		return ilib.mod(ilib.String._fncs.getValue(rule[0], n), ilib.String._fncs.getValue(rule[1], n));
3524 	},
3525 	
3526 	/**
3527 	 * @private
3528 	 * @param {Object} rule
3529 	 * @param {number} n
3530 	 * @return {number}
3531 	 */
3532 	n: function(rule, n) {
3533 		return n;
3534 	},
3535 	
3536 	/**
3537 	 * @private
3538 	 * @param {Object} rule
3539 	 * @param {number} n
3540 	 * @return {boolean}
3541 	 */
3542 	or: function(rule, n) {
3543 		return ilib.String._fncs.getValue(rule[0], n) || ilib.String._fncs.getValue(rule[1], n);
3544 	},
3545 	
3546 	/**
3547 	 * @private
3548 	 * @param {Object} rule
3549 	 * @param {number} n
3550 	 * @return {boolean}
3551 	 */
3552 	and: function(rule, n) {
3553 		return ilib.String._fncs.getValue(rule[0], n) && ilib.String._fncs.getValue(rule[1], n);
3554 	}
3555 };
3556 
3557 ilib.String.prototype = {
3558 	/**
3559 	 * Return the length of this string in characters. This function defers to the regular
3560 	 * Javascript string class in order to perform the length function. Please note that this
3561 	 * method is a real method, whereas the length property of Javascript strings is 
3562 	 * implemented by native code and appears as a property.<p>
3563 	 * 
3564 	 * Example:
3565 	 * 
3566 	 * <pre>
3567 	 * var str = new ilib.String("this is a string");
3568 	 * console.log("String is " + str._length() + " characters long.");
3569 	 * </pre>
3570 	 * @private
3571 	 */
3572 	_length: function () {
3573 		return this.str.length;
3574 	},
3575 	
3576 	/**
3577 	 * Format this string instance as a message, replacing the parameters with 
3578 	 * the given values.<p>
3579 	 * 
3580 	 * The string can contain any text that a regular Javascript string can
3581 	 * contain. Replacement parameters have the syntax:
3582 	 * 
3583 	 * <pre>
3584 	 * {name}
3585 	 * </pre>
3586 	 * 
3587 	 * Where "name" can be any string surrounded by curly brackets. The value of 
3588 	 * "name" is taken from the parameters argument.<p>
3589 	 * 
3590 	 * Example:
3591 	 * 
3592 	 * <pre>
3593 	 * var str = new ilib.String("There are {num} objects.");
3594 	 * console.log(str.format({
3595 	 *   num: 12
3596 	 * });
3597 	 * </pre>
3598 	 * 
3599 	 * Would give the output:
3600 	 * 
3601 	 * <pre>
3602 	 * There are 12 objects.
3603 	 * </pre>
3604 	 * 
3605 	 * If a property is missing from the parameter block, the replacement
3606 	 * parameter substring is left untouched in the string, and a different
3607 	 * set of parameters may be applied a second time. This way, different
3608 	 * parts of the code may format different parts of the message that they
3609 	 * happen to know about.<p>
3610 	 * 
3611 	 * Example:
3612 	 * 
3613 	 * <pre>
3614 	 * var str = new ilib.String("There are {num} objects in the {container}.");
3615 	 * console.log(str.format({
3616 	 *   num: 12
3617 	 * });
3618 	 * </pre>
3619 	 * 
3620 	 * Would give the output:<p>
3621 	 * 
3622 	 * <pre>
3623 	 * There are 12 objects in the {container}.
3624 	 * </pre>
3625 	 * 
3626 	 * The result can then be formatted again with a different parameter block that
3627 	 * specifies a value for the container property.
3628 	 * 
3629 	 * @param params a Javascript object containing values for the replacement 
3630 	 * parameters in the current string
3631 	 * @return a new ilib.String instance with as many replacement parameters filled
3632 	 * out as possible with real values.
3633 	 */
3634 	format: function (params) {
3635 		var formatted = this.str;
3636 		if (params) {
3637 			var regex;
3638 			for (var p in params) {
3639 				if (typeof(params[p]) !== 'undefined') {
3640 					regex = new RegExp("\{"+p+"\}", "g");
3641 					formatted = formatted.replace(regex, params[p]);
3642 				}
3643 			}
3644 		}
3645 		return formatted.toString();
3646 	},
3647 	
3648 	/**
3649 	 * Format a string as one of a choice of strings dependent on the value of
3650 	 * a particular argument index.<p>
3651 	 * 
3652 	 * The syntax of the choice string is as follows. The string contains a
3653 	 * series of choices separated by a vertical bar character "|". Each choice
3654 	 * has a value or range of values to match followed by a hash character "#"
3655 	 * followed by the string to use if the variable matches the criteria.<p>
3656 	 * 
3657 	 * Example string:
3658 	 * 
3659 	 * <pre>
3660 	 * var num = 2;
3661 	 * var str = new ilib.String("0#There are no objects.|1#There is one object.|2#There are {number} objects.");
3662 	 * console.log(str.formatChoice(num, {
3663 	 *   number: num
3664 	 * }));
3665 	 * </pre>
3666 	 * 
3667 	 * Gives the output:
3668 	 * 
3669 	 * <pre>
3670 	 * "There are 2 objects."
3671 	 * </pre>
3672 	 * 
3673 	 * The strings to format may contain replacement variables that will be formatted
3674 	 * using the format() method above and the params argument as a source of values
3675 	 * to use while formatting those variables.<p>
3676 	 * 
3677 	 * If the criterion for a particular choice is empty, that choice will be used
3678 	 * as the default one for use when none of the other choice's criteria match.<p>
3679 	 * 
3680 	 * Example string:
3681 	 * 
3682 	 * <pre>
3683 	 * var num = 22;
3684 	 * var str = new ilib.String("0#There are no objects.|1#There is one object.|#There are {number} objects.");
3685 	 * console.log(str.formatChoice(num, {
3686 	 *   number: num
3687 	 * }));
3688 	 * </pre>
3689 	 * 
3690 	 * Gives the output:
3691 	 * 
3692 	 * <pre>
3693 	 * "There are 22 objects."
3694 	 * </pre>
3695 	 * 
3696 	 * If multiple choice patterns can match a given argument index, the first one 
3697 	 * encountered in the string will be used. If no choice patterns match the 
3698 	 * argument index, then the default choice will be used. If there is no default
3699 	 * choice defined, then this method will return an empty string.<p>
3700 	 * 
3701 	 * <b>Special Syntax</b><p>
3702 	 * 
3703 	 * For any choice format string, all of the patterns in the string should be
3704 	 * of a single type: numeric, boolean, or string/regexp. The type of the 
3705 	 * patterns is determined by the type of the argument index parameter.<p>
3706 	 * 
3707 	 * If the argument index is numeric, then some special syntax can be used 
3708 	 * in the patterns to match numeric ranges.<p>
3709 	 * 
3710 	 * <ul>
3711 	 * <li><i>>x</i> - match any number that is greater than x 
3712 	 * <li><i>>=x</i> - match any number that is greater than or equal to x
3713 	 * <li><i><x</i> - match any number that is less than x
3714 	 * <li><i><=x</i> - match any number that is less than or equal to x
3715 	 * <li><i>start-end</i> - match any number in the range [start,end)
3716 	 * <li><i>zero</i> - match any number in the class "zero". (See below for
3717 	 * a description of number classes.)
3718 	 * <li><i>one</i> - match any number in the class "one"
3719 	 * <li><i>two</i> - match any number in the class "two"
3720 	 * <li><i>few</i> - match any number in the class "few"
3721 	 * <li><i>many</i> - match any number in the class "many"
3722 	 * </ul>
3723 	 * 
3724 	 * A number class defines a set of numbers that receive a particular syntax
3725 	 * in the strings. For example, in Slovenian, integers ending in the digit
3726 	 * "1" are in the "one" class, including 1, 21, 31, ... 101, 111, etc.
3727 	 * Similarly, integers ending in the digit "2" are in the "two" class. 
3728 	 * Integers ending in the digits "3" or "4" are in the "few" class, and
3729 	 * every other integer is handled by the default string.<p>
3730 	 * 
3731 	 * The definition of what numbers are included in a class is locale-dependent.
3732 	 * They are defined in the data file plurals.json. If your string is in a
3733 	 * different locale than the default for ilib, you should call the setLocale()
3734 	 * method of the string instance before calling this method.<p> 
3735 	 * 
3736 	 * <b>Other Pattern Types</b><p>
3737 	 * 
3738 	 * If the argument index is a boolean, the string values "true" and "false" 
3739 	 * may appear as the choice patterns.<p>
3740 	 * 
3741 	 * If the argument index is of type string, then the choice patterns may contain
3742 	 * regular expressions, or static strings as degenerate regexps.
3743 	 * 
3744 	 * @param {*} argIndex The index into the choice array of the current parameter
3745 	 * @param {Object} params The hash of parameter values that replace the replacement 
3746 	 * variables in the string
3747 	 * @throws "syntax error in choice format pattern: " if there is a syntax error
3748 	 * @return {string} the formatted string
3749 	 */
3750 	formatChoice: function(argIndex, params) {
3751 		var choices = this.str.split("|");
3752 		var type = typeof(argIndex);
3753 		var limits = [];
3754 		var strings = [];
3755 		var i;
3756 		var parts;
3757 		var limit;
3758 		var arg;
3759 		var result = undefined;
3760 		var defaultCase = "";
3761 	
3762 		if (this.str.length === 0) {
3763 			// nothing to do
3764 			return "";
3765 		}
3766 		
3767 		// first parse all the choices
3768 		for (i = 0; i < choices.length; i++) {		
3769 			parts = choices[i].split("#");		
3770 			if (parts.length > 2) {
3771 				limits[i] = parts[0];
3772 				parts = parts.shift();			
3773 				strings[i] = parts.join("#");
3774 			} else if (parts.length === 2) {
3775 				limits[i] = parts[0];
3776 				strings[i] = parts[1];
3777 			} else {
3778 				// syntax error
3779 				throw "syntax error in choice format pattern: " + choices[i];
3780 			}		
3781 		}
3782 		
3783 		// then apply the argument index
3784 		for (i = 0; i < limits.length; i++) {
3785 			if (limits[i].length === 0) {
3786 				// this is default case
3787 				defaultCase = new ilib.String(strings[i]);			
3788 			} else {
3789 				switch (type) {
3790 					case 'number':
3791 						arg = parseInt(argIndex, 10);
3792 											
3793 						if (limits[i].substring(0,2) === "<=") {						
3794 							limit = parseFloat(limits[i].substring(2));
3795 							if (arg <= limit) {
3796 								result = new ilib.String(strings[i]);
3797 								i = limits.length;
3798 							}
3799 						} else if (limits[i].substring(0,2) === ">=") {						
3800 							limit = parseFloat(limits[i].substring(2));
3801 							if (arg >= limit) {
3802 								result = new ilib.String(strings[i]);
3803 								i = limits.length;
3804 							}
3805 						} else if (limits[i].charAt(0) === "<") {						
3806 							limit = parseFloat(limits[i].substring(1));
3807 							if (arg < limit) {
3808 								result = new ilib.String(strings[i]);
3809 								i = limits.length;
3810 							}
3811 						} else if (limits[i].charAt(0) === ">") {						
3812 							limit = parseFloat(limits[i].substring(1));
3813 							if (arg > limit) {
3814 								result = new ilib.String(strings[i]);
3815 								i = limits.length;
3816 							}
3817 						} else {
3818 							this.locale = this.locale || new ilib.Locale(this.localeSpec);
3819 							switch (limits[i]) {
3820 								case "zero":
3821 								case "one":
3822 								case "two":
3823 								case "few":
3824 								case "many":
3825 									// CLDR locale-dependent number classes
3826 									var ruleset = ilib.data["plurals_" + this.locale.getLanguage()];
3827 									if (ruleset) {
3828 										var rule = ruleset[limits[i]];
3829 										if (ilib.String._fncs.getValue(rule, arg)) {
3830 											result = new ilib.String(strings[i]);
3831 											i = limits.length;
3832 										}
3833 									}
3834 									break;
3835 								default:
3836 									var dash = limits[i].indexOf("-");
3837 									if (dash !== -1) {							
3838 										// range
3839 										var start = limits[i].substring(0, dash);
3840 										var end = limits[i].substring(dash+1);							
3841 										if (arg >= parseInt(start, 10) && arg <= parseInt(end, 10)) {								
3842 											result = new ilib.String(strings[i]);
3843 											i = limits.length;
3844 										}
3845 									} else if (arg === parseInt(limits[i], 10)) {							
3846 										// exact amount
3847 										result = new ilib.String(strings[i]);
3848 										i = limits.length;
3849 									}
3850 									break;
3851 							}
3852 						}
3853 						break;
3854 					case 'boolean':					
3855 						if (limits[i] === "true" && argIndex === true) {						
3856 							result = new ilib.String(strings[i]);
3857 							i = limits.length;
3858 						} else if (limits[i] === "false" && argIndex === false) {						
3859 							result = new ilib.String(strings[i]);
3860 							i = limits.length;
3861 						}
3862 						break;
3863 					case 'string':					
3864 						var regexp = new RegExp(limits[i], "i");
3865 						if (regexp.test(argIndex)) {
3866 							result = new ilib.String(strings[i]);
3867 							i = limits.length;
3868 						}
3869 						break;
3870 					case 'object':
3871 						throw "syntax error: fmtChoice parameter for the argument index cannot be an object";
3872 				}
3873 			}
3874 		}
3875 		
3876 		if (!result) {		
3877 			result = defaultCase || new ilib.String("");
3878 		}
3879 		
3880 		result = result.format(params);
3881 		
3882 		return result.toString();
3883 	},
3884 	
3885 	// delegates
3886 	/**
3887 	 * Same as String.toString()
3888 	 * @return {string} this instance as regular Javascript string
3889 	 */
3890 	toString: function () {
3891 		return this.str.toString();
3892 	},
3893 	
3894 	/**
3895 	 * Same as String.valueOf()
3896 	 * @return {string} this instance as a regular Javascript string
3897 	 */
3898 	valueOf: function () {
3899 		return this.str.valueOf();
3900 	},
3901 	
3902 	/**
3903 	 * Same as String.charAt()
3904 	 * @param {number} index the index of the character being sought
3905 	 * @return {ilib.String} the character at the given index
3906 	 */
3907 	charAt: function(index) {
3908 		return new ilib.String(this.str.charAt(index));
3909 	},
3910 	
3911 	/**
3912 	 * Same as String.charCodeAt(). This only reports on 
3913 	 * 2-byte UCS-2 Unicode values, and does not take into
3914 	 * account supplementary characters encoded in UTF-16.
3915 	 * If you would like to take account of those characters,
3916 	 * use codePointAt() instead.
3917 	 * @param {number} index the index of the character being sought
3918 	 * @return {number} the character code of the character at the 
3919 	 * given index in the string 
3920 	 */
3921 	charCodeAt: function(index) {
3922 		return this.str.charCodeAt(index);
3923 	},
3924 	
3925 	/**
3926 	 * Same as String.concat()
3927 	 * @param {string} strings strings to concatenate to the current one
3928 	 * @return {ilib.String} a concatenation of the given strings
3929 	 */
3930 	concat: function(strings) {
3931 		return new ilib.String(this.str.concat(strings));
3932 	},
3933 	
3934 	/**
3935 	 * Same as String.indexOf()
3936 	 * @param {string} searchValue string to search for
3937 	 * @param {number} start index into the string to start searching, or
3938 	 * undefined to search the entire string
3939 	 * @return {number} index into the string of the string being sought,
3940 	 * or -1 if the string is not found 
3941 	 */
3942 	indexOf: function(searchValue, start) {
3943 		return this.str.indexOf(searchValue, start);
3944 	},
3945 	
3946 	/**
3947 	 * Same as String.lastIndexOf()
3948 	 * @param {string} searchValue string to search for
3949 	 * @param {number} start index into the string to start searching, or
3950 	 * undefined to search the entire string
3951 	 * @return {number} index into the string of the string being sought,
3952 	 * or -1 if the string is not found 
3953 	 */
3954 	lastIndexOf: function(searchValue, start) {
3955 		return this.str.lastIndexOf(searchValue, start);
3956 	},
3957 	
3958 	/**
3959 	 * Same as String.match()
3960 	 * @param {string} regexp the regular expression to match
3961 	 * @return {Array.<string>} an array of matches
3962 	 */
3963 	match: function(regexp) {
3964 		return this.str.match(regexp);
3965 	},
3966 	
3967 	/**
3968 	 * Same as String.replace()
3969 	 * @param {string} searchValue a regular expression to search for
3970 	 * @param {string} newValue the string to replace the matches with
3971 	 * @return {ilib.String} a new string with all the matches replaced
3972 	 * with the new value
3973 	 */
3974 	replace: function(searchValue, newValue) {
3975 		return new ilib.String(this.str.replace(searchValue, newValue));
3976 	},
3977 	
3978 	/**
3979 	 * Same as String.search()
3980 	 * @param {string} regexp the regular expression to search for
3981 	 * @return {number} position of the match, or -1 for no match
3982 	 */
3983 	search: function(regexp) {
3984 		return this.str.search(regexp);
3985 	},
3986 	
3987 	/**
3988 	 * Same as String.slice()
3989 	 * @param {number} start first character to include in the string
3990 	 * @param {number} end include all characters up to, but not including
3991 	 * the end character
3992 	 * @return {ilib.String} a slice of the current string
3993 	 */
3994 	slice: function(start, end) {
3995 		return new ilib.String(this.str.slice(start, end));
3996 	},
3997 	
3998 	/**
3999 	 * Same as String.split()
4000 	 * @param {string} separator regular expression to match to find
4001 	 * separations between the parts of the text
4002 	 * @param {number} limit maximum number of items in the final 
4003 	 * output array. Any items beyond that limit will be ignored.
4004 	 * @return {Array.<string>} the parts of the current string split 
4005 	 * by the separator
4006 	 */
4007 	split: function(separator, limit) {
4008 		return this.str.split(separator, limit);
4009 	},
4010 	
4011 	/**
4012 	 * Same as String.substr()
4013 	 * @param {number} start the index of the character that should 
4014 	 * begin the returned substring
4015 	 * @param {number} length the number of characters to return after
4016 	 * the start character.
4017 	 * @return {ilib.String} the requested substring 
4018 	 */
4019 	substr: function(start, length) {
4020 		return new ilib.String(this.str.substr(start, length));
4021 	},
4022 	
4023 	/**
4024 	 * Same as String.substring()
4025 	 * @param {number} from the index of the character that should 
4026 	 * begin the returned substring
4027 	 * @param {number} to the index where to stop the extraction. If
4028 	 * omitted, extracts the rest of the string
4029 	 * @return {ilib.String} the requested substring 
4030 	 */
4031 	substring: function(from, to) {
4032 		return this.str.substring(from, to);
4033 	},
4034 	
4035 	/**
4036 	 * Same as String.toLowerCase(). Note that this method is
4037 	 * not locale-sensitive. 
4038 	 * @return {ilib.String} a string with the first character
4039 	 * lower-cased
4040 	 */
4041 	toLowerCase: function() {
4042 		return this.str.toLowerCase();
4043 	},
4044 	
4045 	/**
4046 	 * Same as String.toUpperCase(). Note that this method is
4047 	 * not locale-sensitive. Use toLocaleUpperCase() instead
4048 	 * to get locale-sensitive behaviour. 
4049 	 * @return {ilib.String} a string with the first character
4050 	 * upper-cased
4051 	 */
4052 	toUpperCase: function() {
4053 		return this.str.toUpperCase();
4054 	},
4055 	
4056 	/**
4057 	 * Convert the character or the surrogate pair at the given
4058 	 * index into the string to a Unicode UCS-4 code point.
4059 	 * @protected
4060 	 * @param {number} index index into the string
4061 	 * @return {number} code point of the character at the
4062 	 * given index into the string
4063 	 */
4064 	_toCodePoint: function (index) {
4065 		return ilib.String.toCodePoint(this.str, index);
4066 	},
4067 	
4068 	/**
4069 	 * Call the callback with each character in the string one at 
4070 	 * a time, taking care to step through the surrogate pairs in 
4071 	 * the UTF-16 encoding properly.<p>
4072 	 * 
4073 	 * The standard Javascript String's charAt() method only
4074 	 * returns a particular 16-bit character in the 
4075 	 * UTF-16 encoding scheme.
4076 	 * If the index to charAt() is pointing to a low- or 
4077 	 * high-surrogate character,
4078 	 * it will return the surrogate character rather 
4079 	 * than the the character 
4080 	 * in the supplementary planes that the two surrogates together 
4081 	 * encode. This function will call the callback with the full
4082 	 * character, making sure to join two  
4083 	 * surrogates into one character in the supplementary planes
4084 	 * where necessary.<p>
4085 	 * 
4086 	 * @param {function(string)} callback a callback function to call with each
4087 	 * full character in the current string
4088 	 */
4089 	forEach: function(callback) {
4090 		if (typeof(callback) === 'function') {
4091 			var it = this.charIterator();
4092 			while (it.hasNext()) {
4093 				callback(it.next());
4094 			}
4095 		}
4096 	},
4097 
4098 	/**
4099 	 * Call the callback with each numeric code point in the string one at 
4100 	 * a time, taking care to step through the surrogate pairs in 
4101 	 * the UTF-16 encoding properly.<p>
4102 	 * 
4103 	 * The standard Javascript String's charCodeAt() method only
4104 	 * returns information about a particular 16-bit character in the 
4105 	 * UTF-16 encoding scheme.
4106 	 * If the index to charCodeAt() is pointing to a low- or 
4107 	 * high-surrogate character,
4108 	 * it will return the code point of the surrogate character rather 
4109 	 * than the code point of the character 
4110 	 * in the supplementary planes that the two surrogates together 
4111 	 * encode. This function will call the callback with the full
4112 	 * code point of each character, making sure to join two  
4113 	 * surrogates into one code point in the supplementary planes.<p>
4114 	 * 
4115 	 * @param {function(string)} callback a callback function to call with each
4116 	 * code point in the current string
4117 	 */
4118 	forEachCodePoint: function(callback) {
4119 		if (typeof(callback) === 'function') {
4120 			var it = this.iterator();
4121 			while (it.hasNext()) {
4122 				callback(it.next());
4123 			}
4124 		}
4125 	},
4126 
4127 	/**
4128 	 * Return an iterator that will step through all of the characters
4129 	 * in the string one at a time and return their code points, taking 
4130 	 * care to step through the surrogate pairs in UTF-16 encoding 
4131 	 * properly.<p>
4132 	 * 
4133 	 * The standard Javascript String's charCodeAt() method only
4134 	 * returns information about a particular 16-bit character in the 
4135 	 * UTF-16 encoding scheme.
4136 	 * If the index is pointing to a low- or high-surrogate character,
4137 	 * it will return a code point of the surrogate character rather 
4138 	 * than the code point of the character 
4139 	 * in the supplementary planes that the two surrogates together 
4140 	 * encode.<p>
4141 	 * 
4142 	 * The iterator instance returned has two methods, hasNext() which
4143 	 * returns true if the iterator has more code points to iterate through,
4144 	 * and next() which returns the next code point as a number.<p>
4145 	 * 
4146 	 * @return {Object} an iterator 
4147 	 * that iterates through all the code points in the string
4148 	 */
4149 	iterator: function() {
4150 		/**
4151 		 * @constructor
4152 		 */
4153 		function _iterator (istring) {
4154 			this.index = 0;
4155 			this.hasNext = function () {
4156 				return (this.index < istring.str.length);
4157 			};
4158 			this.next = function () {
4159 				if (this.index < istring.str.length) {
4160 					var num = istring._toCodePoint(this.index);
4161 					this.index += ((num > 0xFFFF) ? 2 : 1);
4162 				} else {
4163 					num = -1;
4164 				}
4165 				return num;
4166 			};
4167 		};
4168 		return new _iterator(this);
4169 	},
4170 
4171 	/**
4172 	 * Return an iterator that will step through all of the characters
4173 	 * in the string one at a time, taking 
4174 	 * care to step through the surrogate pairs in UTF-16 encoding 
4175 	 * properly.<p>
4176 	 * 
4177 	 * The standard Javascript String's charAt() method only
4178 	 * returns information about a particular 16-bit character in the 
4179 	 * UTF-16 encoding scheme.
4180 	 * If the index is pointing to a low- or high-surrogate character,
4181 	 * it will return that surrogate character rather 
4182 	 * than the surrogate pair which represents a character 
4183 	 * in the supplementary planes.<p>
4184 	 * 
4185 	 * The iterator instance returned has two methods, hasNext() which
4186 	 * returns true if the iterator has more characters to iterate through,
4187 	 * and next() which returns the next character.<p>
4188 	 * 
4189 	 * @return {Object} an iterator 
4190 	 * that iterates through all the characters in the string
4191 	 */
4192 	charIterator: function() {
4193 		/**
4194 		 * @constructor
4195 		 */
4196 		function _chiterator (istring) {
4197 			this.index = 0;
4198 			this.hasNext = function () {
4199 				return (this.index < istring.str.length);
4200 			};
4201 			this.next = function () {
4202 				var ch;
4203 				if (this.index < istring.str.length) {
4204 					ch = istring.str.charAt(this.index);
4205 					if (ilib.String._isSurrogate(ch) && 
4206 							this.index+1 < istring.str.length && 
4207 							ilib.String._isSurrogate(istring.str.charAt(this.index+1))) {
4208 						this.index++;
4209 						ch += istring.str.charAt(this.index);
4210 					}
4211 					this.index++;
4212 				}
4213 				return ch;
4214 			};
4215 		};
4216 		return new _chiterator(this);
4217 	},
4218 	
4219 	/**
4220 	 * Return the code point at the given index when the string is viewed 
4221 	 * as an array of code points. If the index is beyond the end of the
4222 	 * array of code points or if the index is negative, -1 is returned.
4223 	 * @param {number} index index of the code point 
4224 	 * @return {number} code point of the character at the given index into
4225 	 * the string
4226 	 */
4227 	codePointAt: function (index) {
4228 		if (index < 0) {
4229 			return -1;
4230 		}
4231 		var count,
4232 			it = this.iterator(),
4233 			ch;
4234 		for (count = index; count >= 0 && it.hasNext(); count--) {
4235 			ch = it.next();
4236 		}
4237 		return (count < 0) ? ch : -1;
4238 	},
4239 	
4240 	/**
4241 	 * Set the locale to use when processing choice formats. The locale
4242 	 * affects how number classes are interpretted. In some cultures,
4243 	 * the limit "few" maps to "any integer that ends in the digits 2 to 9" and
4244 	 * in yet others, "few" maps to "any integer that ends in the digits
4245 	 * 3 or 4".
4246 	 * @param {ilib.Locale|string} locale locale to use when processing choice
4247 	 * formats with this string
4248 	 * @param {boolean=} sync [optional] whether to load the locale data synchronously 
4249 	 * or not
4250 	 * @param {Object=} loadParams [optional] parameters to pass to the loader function
4251 	 * @param {function(*)=} onLoad [optional] function to call when the loading is done
4252 	 */
4253 	setLocale: function (locale, sync, loadParams, onLoad) {
4254 		if (typeof(locale) === 'object') {
4255 			this.locale = locale;
4256 		} else {
4257 			this.localeSpec = locale;
4258 			this.locale = new ilib.Locale(locale);
4259 		}
4260 		
4261 		ilib.String.loadPlurals(typeof(sync) !== 'undefined' ? sync : true, this.locale, loadParams, onLoad);
4262 	},
4263 
4264 	/**
4265 	 * Return the locale to use when processing choice formats. The locale
4266 	 * affects how number classes are interpretted. In some cultures,
4267 	 * the limit "few" maps to "any integer that ends in the digits 2 to 9" and
4268 	 * in yet others, "few" maps to "any integer that ends in the digits
4269 	 * 3 or 4".
4270 	 * @return {string} localespec to use when processing choice
4271 	 * formats with this string
4272 	 */
4273 	getLocale: function () {
4274 		return (this.locale ? this.locale.getSpec() : this.localeSpec) || ilib.getLocale();
4275 	},
4276 
4277 	/**
4278 	 * Return the number of code points in this string. This may be different
4279 	 * than the number of characters, as the UTF-16 encoding that Javascript
4280 	 * uses for its basis returns surrogate pairs separately. Two 2-byte 
4281 	 * surrogate characters together make up one character/code point in 
4282 	 * the supplementary character planes. If your string contains no
4283 	 * characters in the supplementary planes, this method will return the
4284 	 * same thing as the length() method.
4285 	 * @return {number} the number of code points in this string
4286 	 */
4287 	codePointLength: function () {
4288 		if (this.cpLength === -1) {
4289 			var it = this.iterator();
4290 			this.cpLength = 0;
4291 			while (it.hasNext()) { 
4292 				this.cpLength++;
4293 				it.next();
4294 			};
4295 		}
4296 		return this.cpLength;	
4297 	}
4298 };
4299 /*
4300  * calendar.js - Represent a calendar object.
4301  * 
4302  * Copyright © 2012, JEDLSoft
4303  *
4304  * Licensed under the Apache License, Version 2.0 (the "License");
4305  * you may not use this file except in compliance with the License.
4306  * You may obtain a copy of the License at
4307  *
4308  *     http://www.apache.org/licenses/LICENSE-2.0
4309  *
4310  * Unless required by applicable law or agreed to in writing, software
4311  * distributed under the License is distributed on an "AS IS" BASIS,
4312  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4313  *
4314  * See the License for the specific language governing permissions and
4315  * limitations under the License.
4316  */
4317 
4318 /* !depends
4319 ilibglobal.js
4320 locale.js
4321 localeinfo.js
4322 */
4323 
4324 /**
4325  * Interface that all calendars must implement.
4326  * 
4327  * Depends directive: !depends calendar.js
4328  * 
4329  * @interface
4330  * @protected
4331  */
4332 ilib.Cal = function() {
4333 };
4334 
4335 /**
4336  * Factory method to create a new instance of a calendar subclass.<p>
4337  * 
4338  * The options parameter can be an object that contains the following
4339  * properties:
4340  * 
4341  * <ul>
4342  * <li><i>type</i> - specify the type of the calendar desired. The
4343  * list of valid values changes depending on which calendars are 
4344  * defined. When assembling your iliball.js, include those calendars 
4345  * you wish to use in your program or web page, and they will register 
4346  * themselves with this factory method. The "official", "gregorian",
4347  * and "julian" calendars are all included by default, as they are the
4348  * standard calendars for much of the world.
4349  * <li><i>locale</i> - some calendars vary depending on the locale.
4350  * For example, the "official" calendar transitions from a Julian-style
4351  * calendar to a Gregorian-style calendar on a different date for
4352  * each country, as the governments of those countries decided to
4353  * adopt the Gregorian calendar at different times. 
4354  * </ul>
4355  * 
4356  * If a locale is specified, but no type, then the calendar that is default for
4357  * the locale will be instantiated and returned. If neither the type nor
4358  * the locale are specified, then the calendar for the default locale will
4359  * be used. 
4360  * 
4361  * @param {Object=} options options controlling the construction of this instance, or
4362  * undefined to use the default options
4363  * @return {ilib.Cal} an instance of a calendar object of the appropriate type
4364  */
4365 ilib.Cal.newInstance = function (options) {
4366 	var locale = options && options.locale,
4367 	type = options && options.type,
4368 	cons;
4369 
4370 	if (!locale) {
4371 		locale = new ilib.Locale();	// default locale
4372 	}
4373 	
4374 	if (!type) {
4375 		var info = new ilib.LocaleInfo(locale);
4376 		type = info.getCalendar();
4377 	}
4378 	
4379 	cons = ilib.Cal._constructors[type];
4380 	
4381 	// pass the same options through to the constructor so the subclass
4382 	// has the ability to do something with if it needs to
4383 	return cons && new cons(options);
4384 };
4385 
4386 /* place for the subclasses to put their constructors so that the factory method
4387  * can find them. Do this to add your calendar after it's defined: 
4388  * ilib.Cal._constructors["mytype"] = ilib.Cal.MyTypeConstructor;
4389  */
4390 ilib.Cal._constructors = {};
4391 
4392 /**
4393  * Return an array of known calendar types that the factory method can instantiate.
4394  * 
4395  * @return {Array.<string>} an array of calendar types
4396  */
4397 ilib.Cal.getCalendars = function () {
4398 	var arr = [],
4399 		c;
4400 	
4401 	for (c in ilib.Cal._constructors) {
4402 		if (c && ilib.Cal._constructors[c]) {
4403 			arr.push(c); // code like a pirate
4404 		}
4405 	}
4406 	
4407 	return arr;
4408 };
4409 
4410 ilib.Cal.prototype = {
4411 	/**
4412 	 * Return the type of this calendar.
4413 	 * 
4414 	 * @return {string} the name of the type of this calendar 
4415 	 */
4416 	getType: function() {
4417 		throw "Cannot call methods of abstract class ilib.Cal";
4418 	},
4419 	
4420 	/**
4421 	 * Return the number of months in the given year. The number of months in a year varies
4422 	 * for some luni-solar calendars because in some years, an extra month is needed to extend the 
4423 	 * days in a year to an entire solar year. The month is represented as a 1-based number
4424 	 * where 1=first month, 2=second month, etc.
4425 	 * 
4426 	 * @param {number} year a year for which the number of months is sought
4427 	 * @return {number} The number of months in the given year
4428 	 */
4429 	getNumMonths: function(year) {
4430 		throw "Cannot call methods of abstract class ilib.Cal";
4431 	},
4432 	
4433 	/**
4434 	 * Return the number of days in a particular month in a particular year. This function
4435 	 * can return a different number for a month depending on the year because of things
4436 	 * like leap years.
4437 	 * 
4438 	 * @param {number} month the month for which the length is sought
4439 	 * @param {number} year the year within which that month can be found
4440 	 * @return {number} the number of days within the given month in the given year
4441 	 */
4442 	getMonLength: function(month, year) {
4443 		throw "Cannot call methods of abstract class ilib.Cal";
4444 	},
4445 	
4446 	/**
4447 	 * Return true if the given year is a leap year in this calendar.
4448 	 * The year parameter may be given as a number.
4449 	 * 
4450 	 * @param {number} year the year for which the leap year information is being sought
4451 	 * @return {boolean} true if the given year is a leap year
4452 	 */
4453 	isLeapYear: function(year) {
4454 		throw "Cannot call methods of abstract class ilib.Cal";
4455 	}
4456 };
4457 
4458 /*
4459  * julianday.js - A Julian date object.
4460  * 
4461  * Copyright © 2012-2014, JEDLSoft
4462  *
4463  * Licensed under the Apache License, Version 2.0 (the "License");
4464  * you may not use this file except in compliance with the License.
4465  * You may obtain a copy of the License at
4466  *
4467  *     http://www.apache.org/licenses/LICENSE-2.0
4468  *
4469  * Unless required by applicable law or agreed to in writing, software
4470  * distributed under the License is distributed on an "AS IS" BASIS,
4471  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4472  *
4473  * See the License for the specific language governing permissions and
4474  * limitations under the License.
4475  */
4476 
4477 /* !depends locale.js */
4478 
4479 /**
4480  * @class
4481  * A Julian Day class. A Julian Day is a date based on the Julian Day count
4482  * of time invented by Joseph Scaliger in 1583 for use with astronomical calculations. 
4483  * Do not confuse it with a date in the Julian calendar, which it has very
4484  * little in common with. The naming is unfortunately close, and comes from history.<p>
4485  * 
4486  * Depends directive: !depends julianday.js
4487  * 
4488  * @constructor
4489  * @param {number} num the Julian Day expressed as a floating point number 
4490  */
4491 ilib.JulianDay = function(num) {
4492 	this.jd = num;
4493 	this.days = Math.floor(this.jd);
4494 	this.frac = num - this.days;
4495 };
4496 
4497 ilib.JulianDay.prototype = {
4498 	/**
4499 	 * Return the integral portion of this Julian Day instance. This corresponds to
4500 	 * the number of days since the beginning of the epoch.
4501 	 * 
4502 	 * @return {number} the integral portion of this Julian Day
4503 	 */
4504 	getDays: function() {
4505 		return this.days;
4506 	},
4507 	
4508 	/**
4509 	 * Set the date of this Julian Day instance.
4510 	 * 
4511 	 * @param {number} days the julian date expressed as a floating point number
4512 	 */
4513 	setDays: function(days) {
4514 		this.days = Math.floor(days);
4515 		this.jd = this.days + this.frac;
4516 	},
4517 	
4518 	/**
4519 	 * Return the fractional portion of this Julian Day instance. This portion 
4520 	 * corresponds to the time of day for the instance.
4521 	 */
4522 	getDayFraction: function() {
4523 		return this.frac;
4524 	},
4525 	
4526 	/**
4527 	 * Set the fractional part of the Julian Day. The fractional part represents
4528 	 * the portion of a fully day. Julian dates start at noon, and proceed until
4529 	 * noon of the next day. That would mean midnight is represented as a fractional
4530 	 * part of 0.5.
4531 	 * 
4532 	 * @param {number} fraction The fractional part of the Julian date
4533 	 */
4534 	setDayFraction: function(fraction) {
4535 		var t = Math.floor(fraction);
4536 		this.frac = fraction - t;
4537 		this.jd = this.days + this.frac;
4538 	},
4539 	
4540 	/** 
4541 	 * Return the Julian Day expressed as a floating point number.
4542 	 * @return {number} the Julian Day as a number
4543 	 */
4544 	getDate: function () {
4545 		return this.jd;
4546 	},
4547 	
4548 	/**
4549 	 * Set the date of this Julian Day instance.
4550 	 * 
4551 	 * @param {number} num the numeric Julian Day to set into this instance
4552 	 */
4553 	setDate: function (num) {
4554 		this.jd = num;
4555 	},
4556 	
4557 	/**
4558 	 * Add an offset to the current date instance. The offset should be expressed in
4559 	 * terms of Julian days. That is, each integral unit represents one day of time, and
4560 	 * fractional part represents a fraction of a regular 24-hour day.
4561 	 * 
4562 	 * @param {number} offset an amount to add (or subtract) to the current result instance.
4563 	 */
4564 	addDate: function(offset) {
4565 		if (typeof(offset) === 'number') {
4566 			this.jd += offset;
4567 			this.days = Math.floor(this.jd);
4568 			this.frac = this.jd - this.days;
4569 		}
4570 	}
4571 };
4572 
4573 /*
4574  * gregorian.js - Represent a Gregorian calendar object.
4575  * 
4576  * Copyright © 2012-2014, JEDLSoft
4577  *
4578  * Licensed under the Apache License, Version 2.0 (the "License");
4579  * you may not use this file except in compliance with the License.
4580  * You may obtain a copy of the License at
4581  *
4582  *     http://www.apache.org/licenses/LICENSE-2.0
4583  *
4584  * Unless required by applicable law or agreed to in writing, software
4585  * distributed under the License is distributed on an "AS IS" BASIS,
4586  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4587  *
4588  * See the License for the specific language governing permissions and
4589  * limitations under the License.
4590  */
4591 
4592 
4593 /* !depends calendar.js locale.js date.js julianday.js util/utils.js util/math.js */
4594 
4595 /**
4596  * @class
4597  * Construct a new Gregorian calendar object. This class encodes information about
4598  * a Gregorian calendar.<p>
4599  * 
4600  * Depends directive: !depends gregorian.js
4601  * 
4602  * @constructor
4603  * @implements ilib.Cal
4604  */
4605 ilib.Cal.Gregorian = function() {
4606 	this.type = "gregorian";
4607 };
4608 
4609 /**
4610  * the lengths of each month 
4611  * @private
4612  * @const
4613  * @type Array.<number> 
4614  */
4615 ilib.Cal.Gregorian.monthLengths = [
4616 	31,  /* Jan */
4617 	28,  /* Feb */
4618 	31,  /* Mar */
4619 	30,  /* Apr */
4620 	31,  /* May */
4621 	30,  /* Jun */
4622 	31,  /* Jul */
4623 	31,  /* Aug */
4624 	30,  /* Sep */
4625 	31,  /* Oct */
4626 	30,  /* Nov */
4627 	31   /* Dec */
4628 ];
4629 
4630 /**
4631  * Return the number of months in the given year. The number of months in a year varies
4632  * for some luni-solar calendars because in some years, an extra month is needed to extend the 
4633  * days in a year to an entire solar year. The month is represented as a 1-based number
4634  * where 1=first month, 2=second month, etc.
4635  * 
4636  * @param {number} year a year for which the number of months is sought
4637  * @return {number} The number of months in the given year
4638  */
4639 ilib.Cal.Gregorian.prototype.getNumMonths = function(year) {
4640 	return 12;
4641 };
4642 
4643 /**
4644  * Return the number of days in a particular month in a particular year. This function
4645  * can return a different number for a month depending on the year because of things
4646  * like leap years.
4647  * 
4648  * @param {number} month the month for which the length is sought
4649  * @param {number} year the year within which that month can be found
4650  * @return {number} the number of days within the given month in the given year
4651  */
4652 ilib.Cal.Gregorian.prototype.getMonLength = function(month, year) {
4653 	if (month !== 2 || !this.isLeapYear(year)) {
4654 		return ilib.Cal.Gregorian.monthLengths[month-1];
4655 	} else {
4656 		return 29;
4657 	}
4658 };
4659 
4660 /**
4661  * Return true if the given year is a leap year in the Gregorian calendar.
4662  * The year parameter may be given as a number, or as a GregDate object.
4663  * @param {number|ilib.Date.GregDate} year the year for which the leap year information is being sought
4664  * @return {boolean} true if the given year is a leap year
4665  */
4666 ilib.Cal.Gregorian.prototype.isLeapYear = function(year) {
4667 	var y = (typeof(year) === 'number' ? year : year.getYears());
4668 	var centuries = ilib.mod(y, 400);
4669 	return (ilib.mod(y, 4) === 0 && centuries !== 100 && centuries !== 200 && centuries !== 300);
4670 };
4671 
4672 /**
4673  * Return the type of this calendar.
4674  * 
4675  * @return {string} the name of the type of this calendar 
4676  */
4677 ilib.Cal.Gregorian.prototype.getType = function() {
4678 	return this.type;
4679 };
4680 
4681 /**
4682  * Return a date instance for this calendar type using the given
4683  * options.
4684  * @param {Object} options options controlling the construction of 
4685  * the date instance
4686  * @return {ilib.Date} a date appropriate for this calendar type
4687  */
4688 ilib.Cal.Gregorian.prototype.newDateInstance = function (options) {
4689 	return new ilib.Date.GregDate(options);
4690 };
4691 
4692 /* register this calendar for the factory method */
4693 ilib.Cal._constructors["gregorian"] = ilib.Cal.Gregorian;
4694 
4695 /*
4696  * ratadie.js - Represent the RD date number in the calendar
4697  * 
4698  * Copyright © 2014, JEDLSoft
4699  *
4700  * Licensed under the Apache License, Version 2.0 (the "License");
4701  * you may not use this file except in compliance with the License.
4702  * You may obtain a copy of the License at
4703  *
4704  *     http://www.apache.org/licenses/LICENSE-2.0
4705  *
4706  * Unless required by applicable law or agreed to in writing, software
4707  * distributed under the License is distributed on an "AS IS" BASIS,
4708  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4709  *
4710  * See the License for the specific language governing permissions and
4711  * limitations under the License.
4712  */
4713 
4714 /* !depends 
4715 util/utils.js
4716 util/math.js
4717 julianday.js 
4718 */
4719 
4720 /**
4721  * @class
4722  * Construct a new RD date number object. The constructor parameters can 
4723  * contain any of the following properties:
4724  * 
4725  * <ul>
4726  * <li><i>unixtime<i> - sets the time of this instance according to the given 
4727  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
4728  * 
4729  * <li><i>julianday</i> - sets the time of this instance according to the given
4730  * Julian Day instance or the Julian Day given as a float
4731  * 
4732  * <li><i>cycle</i> - any integer giving the number of 60-year cycle in which the date is located.
4733  * If the cycle is not given but the year is, it is assumed that the year parameter is a fictitious 
4734  * linear count of years since the beginning of the epoch, much like other calendars. This linear
4735  * count is never used. If both the cycle and year are given, the year is wrapped to the range 0 
4736  * to 60 and treated as if it were a year in the regular 60-year cycle.
4737  * 
4738  * <li><i>year</i> - any integer, including 0
4739  * 
4740  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
4741  * 
4742  * <li><i>day</i> - 1 to 31
4743  * 
4744  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
4745  * is always done with an unambiguous 24 hour representation
4746  * 
4747  * <li><i>minute</i> - 0 to 59
4748  * 
4749  * <li><i>second</i> - 0 to 59
4750  * 
4751  * <li><i>millisecond</i> - 0 to 999
4752  * 
4753  * <li><i>parts</i> - 0 to 1079. Specify the halaqim parts of an hour. Either specify 
4754  * the parts or specify the minutes, seconds, and milliseconds, but not both. This is only used
4755  * in the Hebrew calendar. 
4756  * 
4757  * <li><i>minute</i> - 0 to 59
4758  * 
4759  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
4760  * </ul>
4761  *
4762  * If the constructor is called with another date instance instead of
4763  * a parameter block, the other instance acts as a parameter block and its
4764  * settings are copied into the current instance.<p>
4765  * 
4766  * If the constructor is called with no arguments at all or if none of the 
4767  * properties listed above are present, then the RD is calculate based on 
4768  * the current date at the time of instantiation. <p>
4769  * 
4770  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
4771  * specified in the params, it is assumed that they have the smallest possible
4772  * value in the range for the property (zero or one).<p>
4773  * 
4774  * Depends directive: !depends ratadie.js
4775  * 
4776  * @private
4777  * @constructor
4778  * @param {Object=} params parameters that govern the settings and behaviour of this RD date
4779  */
4780 ilib.Date.RataDie = function(params) {
4781 	if (params) {
4782 		if (typeof(params.date) !== 'undefined') {
4783 			// accept JS Date classes or strings
4784 			var date = params.date;
4785 			if (!(date instanceof Date)) {
4786 				date = new Date(date); // maybe a string initializer?
4787 			}
4788 			this._setTime(date.getTime());
4789 		} else if (typeof(params.unixtime) !== 'undefined') {
4790 			this._setTime(parseInt(params.unixtime, 10));
4791 		} else if (typeof(params.julianday) !== 'undefined') {
4792 			// JD time is defined to be UTC
4793 			this._setJulianDay(parseFloat(params.julianday));
4794 		} else if (params.year || params.month || params.day || params.hour ||
4795 				params.minute || params.second || params.millisecond || params.parts || params.cycle) {
4796 			this._setDateComponents(params);
4797 		} else if (typeof(params.rd) !== 'undefined') {
4798 			this.rd = (typeof(params.rd) === 'object' && params.rd instanceof ilib.Date.RataDie) ? params.rd.rd : params.rd;
4799 		}
4800 	}
4801 	
4802 	/**
4803 	 * @type {number} the Rata Die number of this date for this calendar type
4804 	 */
4805 	if (typeof(this.rd) === 'undefined') {
4806 		var now = new Date();
4807 		this._setTime(now.getTime());
4808 	}
4809 };
4810 
4811 /**
4812  * @private
4813  * @const
4814  * @type {number}
4815  */
4816 ilib.Date.RataDie.gregorianEpoch = 1721424.5;
4817 
4818 ilib.Date.RataDie.prototype = {
4819 	/**
4820 	 * @protected
4821 	 * @const
4822 	 * @type {number}
4823 	 * the difference between a zero Julian day and the zero Gregorian date. 
4824 	 */
4825 	epoch: ilib.Date.RataDie.gregorianEpoch,
4826 	
4827 	/**
4828 	 * Set the RD of this instance according to the given unix time. Unix time is
4829 	 * the number of milliseconds since midnight on Jan 1, 1970.
4830 	 *
4831 	 * @protected
4832 	 * @param {number} millis the unix time to set this date to in milliseconds 
4833 	 */
4834 	_setTime: function(millis) {
4835 		// 2440587.5 is the julian day of midnight Jan 1, 1970, UTC (Gregorian)
4836 		this._setJulianDay(2440587.5 + millis / 86400000);
4837 	},
4838 
4839 	/**
4840 	 * Set the date of this instance using a Julian Day.
4841 	 * @protected
4842 	 * @param {number} date the Julian Day to use to set this date
4843 	 */
4844 	_setJulianDay: function (date) {
4845 		var jd = (typeof(date) === 'number') ? new ilib.JulianDay(date) : date;
4846 		// round to the nearest millisecond
4847 		this.rd = ilib._roundFnc.halfup((jd.getDate() - this.epoch) * 86400000) / 86400000;
4848 	},
4849 
4850 	/**
4851 	 * Return the rd number of the particular day of the week on or before the 
4852 	 * given rd. eg. The Sunday on or before the given rd.
4853 	 * @protected
4854 	 * @param {number} rd the rata die date of the reference date
4855 	 * @param {number} dayOfWeek the day of the week that is being sought relative 
4856 	 * to the current date
4857 	 * @return {number} the rd of the day of the week
4858 	 */
4859 	_onOrBefore: function(rd, dayOfWeek) {
4860 		return rd - ilib.mod(Math.floor(rd) - dayOfWeek - 2, 7);
4861 	},
4862 	
4863 	/**
4864 	 * Return the rd number of the particular day of the week on or before the current rd.
4865 	 * eg. The Sunday on or before the current rd. If the offset is given, the calculation
4866 	 * happens in wall time instead of UTC. UTC time may be a day before or day behind 
4867 	 * wall time, so it it would give the wrong day of the week if this calculation was
4868 	 * done in UTC time when the caller really wanted wall time. Even though the calculation
4869 	 * may be done in wall time, the return value is nonetheless always given in UTC.
4870 	 * @param {number} dayOfWeek the day of the week that is being sought relative 
4871 	 * to the current date
4872 	 * @param {number=} offset RD offset for the time zone. Zero is assumed if this param is
4873 	 * not given
4874 	 * @return {number} the rd of the day of the week
4875 	 */
4876 	onOrBefore: function(dayOfWeek, offset) {
4877 		offset = offset || 0;
4878 		return this._onOrBefore(this.rd + offset, dayOfWeek) - offset;
4879 	},
4880 	
4881 	/**
4882 	 * Return the rd number of the particular day of the week on or before the current rd.
4883 	 * eg. The Sunday on or before the current rd. If the offset is given, the calculation
4884 	 * happens in wall time instead of UTC. UTC time may be a day before or day behind 
4885 	 * wall time, so it it would give the wrong day of the week if this calculation was
4886 	 * done in UTC time when the caller really wanted wall time. Even though the calculation
4887 	 * may be done in wall time, the return value is nonetheless always given in UTC.
4888 	 * @param {number} dayOfWeek the day of the week that is being sought relative 
4889 	 * to the reference date
4890 	 * @param {number=} offset RD offset for the time zone. Zero is assumed if this param is
4891 	 * not given
4892 	 * @return {number} the day of the week
4893 	 */
4894 	onOrAfter: function(dayOfWeek, offset) {
4895 		offset = offset || 0;
4896 		return this._onOrBefore(this.rd+6+offset, dayOfWeek) - offset;
4897 	},
4898 	
4899 	/**
4900 	 * Return the rd number of the particular day of the week before the current rd.
4901 	 * eg. The Sunday before the current rd. If the offset is given, the calculation
4902 	 * happens in wall time instead of UTC. UTC time may be a day before or day behind 
4903 	 * wall time, so it it would give the wrong day of the week if this calculation was
4904 	 * done in UTC time when the caller really wanted wall time. Even though the calculation
4905 	 * may be done in wall time, the return value is nonetheless always given in UTC.
4906 	 * @param {number} dayOfWeek the day of the week that is being sought relative 
4907 	 * to the reference date
4908 	 * @param {number=} offset RD offset for the time zone. Zero is assumed if this param is
4909 	 * not given
4910 	 * @return {number} the day of the week
4911 	 */
4912 	before: function(dayOfWeek, offset) {
4913 		offset = offset || 0;
4914 		return this._onOrBefore(this.rd-1+offset, dayOfWeek) - offset;
4915 	},
4916 	
4917 	/**
4918 	 * Return the rd number of the particular day of the week after the current rd.
4919 	 * eg. The Sunday after the current rd. If the offset is given, the calculation
4920 	 * happens in wall time instead of UTC. UTC time may be a day before or day behind 
4921 	 * wall time, so it it would give the wrong day of the week if this calculation was
4922 	 * done in UTC time when the caller really wanted wall time. Even though the calculation
4923 	 * may be done in wall time, the return value is nonetheless always given in UTC.
4924 	 * @param {number} dayOfWeek the day of the week that is being sought relative 
4925 	 * to the reference date
4926 	 * @param {number=} offset RD offset for the time zone. Zero is assumed if this param is
4927 	 * not given
4928 	 * @return {number} the day of the week
4929 	 */
4930 	after: function(dayOfWeek, offset) {
4931 		offset = offset || 0;
4932 		return this._onOrBefore(this.rd+7+offset, dayOfWeek) - offset;
4933 	},
4934 
4935 	/**
4936 	 * Return the unix time equivalent to this Gregorian date instance. Unix time is
4937 	 * the number of milliseconds since midnight on Jan 1, 1970 UTC. This method only
4938 	 * returns a valid number for dates between midnight, Jan 1, 1970 and  
4939 	 * Jan 19, 2038 at 3:14:07am when the unix time runs out. If this instance 
4940 	 * encodes a date outside of that range, this method will return -1.
4941 	 * 
4942 	 * @return {number} a number giving the unix time, or -1 if the date is outside the
4943 	 * valid unix time range
4944 	 */
4945 	getTime: function() {
4946 		// earlier than Jan 1, 1970
4947 		// or later than Jan 19, 2038 at 3:14:07am
4948 		var jd = this.getJulianDay();
4949 		if (jd < 2440587.5 || jd > 2465442.634803241) { 
4950 			return -1;
4951 		}
4952 	
4953 		// avoid the rounding errors in the floating point math by only using
4954 		// the whole days from the rd, and then calculating the milliseconds directly
4955 		return Math.round((jd - 2440587.5) * 86400000);
4956 	},
4957 
4958 	/**
4959 	 * Return the extended unix time equivalent to this Gregorian date instance. Unix time is
4960 	 * the number of milliseconds since midnight on Jan 1, 1970 UTC. Traditionally unix time
4961 	 * (or the type "time_t" in C/C++) is only encoded with a unsigned 32 bit integer, and thus 
4962 	 * runs out on Jan 19, 2038. However, most Javascript engines encode numbers well above 
4963 	 * 32 bits and the Date object allows you to encode up to 100 million days worth of time 
4964 	 * after Jan 1, 1970, and even more interestingly 100 million days worth of time before
4965 	 * Jan 1, 1970 as well. This method returns the number of milliseconds in that extended 
4966 	 * range. If this instance encodes a date outside of that range, this method will return
4967 	 * NaN.
4968 	 * 
4969 	 * @return {number} a number giving the extended unix time, or NaN if the date is outside 
4970 	 * the valid extended unix time range
4971 	 */
4972 	getTimeExtended: function() {
4973 		var jd = this.getJulianDay();
4974 		
4975 		// test if earlier than Jan 1, 1970 - 100 million days
4976 		// or later than Jan 1, 1970 + 100 million days
4977 		if (jd < -97559412.5 || jd > 102440587.5) { 
4978 			return NaN;
4979 		}
4980 	
4981 		// avoid the rounding errors in the floating point math by only using
4982 		// the whole days from the rd, and then calculating the milliseconds directly
4983 		return Math.round((jd - 2440587.5) * 86400000);
4984 	},
4985 
4986 	/**
4987 	 * Return the Julian Day equivalent to this calendar date as a number.
4988 	 * This returns the julian day in UTC.
4989 	 * 
4990 	 * @return {number} the julian date equivalent of this date
4991 	 */
4992 	getJulianDay: function() {
4993 		return this.rd + this.epoch;
4994 	},
4995 
4996 	/**
4997 	 * Return the Rata Die (fixed day) number of this RD date.
4998 	 * 
4999 	 * @return {number} the rd date as a number
5000 	 */
5001 	getRataDie: function() {
5002 		return this.rd;
5003 	}
5004 };
5005 
5006 /*
5007  * gregratadie.js - Represent the RD date number in the Gregorian calendar
5008  * 
5009  * Copyright © 2014, JEDLSoft
5010  *
5011  * Licensed under the Apache License, Version 2.0 (the "License");
5012  * you may not use this file except in compliance with the License.
5013  * You may obtain a copy of the License at
5014  *
5015  *     http://www.apache.org/licenses/LICENSE-2.0
5016  *
5017  * Unless required by applicable law or agreed to in writing, software
5018  * distributed under the License is distributed on an "AS IS" BASIS,
5019  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5020  *
5021  * See the License for the specific language governing permissions and
5022  * limitations under the License.
5023  */
5024 
5025 /* !depends 
5026 date.js
5027 calendar/gregorian.js
5028 calendar/ratadie.js
5029 util/utils.js
5030 util/math.js
5031 julianday.js 
5032 */
5033 
5034 /**
5035  * @class
5036  * Construct a new Gregorian RD date number object. The constructor parameters can 
5037  * contain any of the following properties:
5038  * 
5039  * <ul>
5040  * <li><i>unixtime<i> - sets the time of this instance according to the given 
5041  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
5042  * 
5043  * <li><i>julianday</i> - sets the time of this instance according to the given
5044  * Julian Day instance or the Julian Day given as a float
5045  * 
5046  * <li><i>year</i> - any integer, including 0
5047  * 
5048  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
5049  * 
5050  * <li><i>day</i> - 1 to 31
5051  * 
5052  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
5053  * is always done with an unambiguous 24 hour representation
5054  * 
5055  * <li><i>minute</i> - 0 to 59
5056  * 
5057  * <li><i>second</i> - 0 to 59
5058  * 
5059  * <li><i>millisecond</i> - 0 to 999
5060  * 
5061  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
5062  * </ul>
5063  *
5064  * If the constructor is called with another Gregorian date instance instead of
5065  * a parameter block, the other instance acts as a parameter block and its
5066  * settings are copied into the current instance.<p>
5067  * 
5068  * If the constructor is called with no arguments at all or if none of the 
5069  * properties listed above are present, then the RD is calculate based on 
5070  * the current date at the time of instantiation. <p>
5071  * 
5072  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
5073  * specified in the params, it is assumed that they have the smallest possible
5074  * value in the range for the property (zero or one).<p>
5075  * 
5076  * Depends directive: !depends gregratadie.js
5077  * 
5078  * @private
5079  * @constructor
5080  * @extends ilib.Date.RataDie
5081  * @param {Object=} params parameters that govern the settings and behaviour of this Gregorian RD date
5082  */
5083 ilib.Date.GregRataDie = function(params) {
5084 	this.cal = params && params.cal || new ilib.Cal.Gregorian();
5085 	/** @type {number|undefined} */
5086 	this.rd = undefined;
5087 	ilib.Date.RataDie.call(this, params);
5088 };
5089 
5090 ilib.Date.GregRataDie.prototype = new ilib.Date.RataDie();
5091 ilib.Date.GregRataDie.prototype.parent = ilib.Date.RataDie;
5092 ilib.Date.GregRataDie.prototype.constructor = ilib.Date.GregRataDie;
5093 
5094 /**
5095  * the cumulative lengths of each month, for a non-leap year 
5096  * @private
5097  * @const
5098  * @type Array.<number>
5099  */
5100 ilib.Date.GregRataDie.cumMonthLengths = [
5101     0,   /* Jan */
5102 	31,  /* Feb */
5103 	59,  /* Mar */
5104 	90,  /* Apr */
5105 	120, /* May */
5106 	151, /* Jun */
5107 	181, /* Jul */
5108 	212, /* Aug */
5109 	243, /* Sep */
5110 	273, /* Oct */
5111 	304, /* Nov */
5112 	334, /* Dec */
5113 	365
5114 ];
5115 
5116 /**
5117  * the cumulative lengths of each month, for a leap year 
5118  * @private
5119  * @const
5120  * @type Array.<number>
5121  */
5122 ilib.Date.GregRataDie.cumMonthLengthsLeap = [
5123 	0,   /* Jan */
5124 	31,  /* Feb */
5125 	60,  /* Mar */
5126 	91,  /* Apr */
5127 	121, /* May */
5128 	152, /* Jun */
5129 	182, /* Jul */
5130 	213, /* Aug */
5131 	244, /* Sep */
5132 	274, /* Oct */
5133 	305, /* Nov */
5134 	335, /* Dec */
5135 	366
5136 ];
5137 
5138 /**
5139  * Calculate the Rata Die (fixed day) number of the given date.
5140  * 
5141  * @private
5142  * @param {Object} date the date components to calculate the RD from
5143  */
5144 ilib.Date.GregRataDie.prototype._setDateComponents = function(date) {
5145 	var year = parseInt(date.year, 10) || 0;
5146 	var month = parseInt(date.month, 10) || 1;
5147 	var day = parseInt(date.day, 10) || 1;
5148 	var hour = parseInt(date.hour, 10) || 0;
5149 	var minute = parseInt(date.minute, 10) || 0;
5150 	var second = parseInt(date.second, 10) || 0;
5151 	var millisecond = parseInt(date.millisecond, 10) || 0;
5152 
5153 	var years = 365 * (year - 1) +
5154 		Math.floor((year-1)/4) -
5155 		Math.floor((year-1)/100) +
5156 		Math.floor((year-1)/400);
5157 	
5158 	var dayInYear = (month > 1 ? ilib.Date.GregRataDie.cumMonthLengths[month-1] : 0) +
5159 		day +
5160 		(ilib.Cal.Gregorian.prototype.isLeapYear.call(this.cal, year) && month > 2 ? 1 : 0);
5161 	var rdtime = (hour * 3600000 +
5162 		minute * 60000 +
5163 		second * 1000 +
5164 		millisecond) / 
5165 		86400000; 
5166 	/*
5167 	debug("getRataDie: converting " +  JSON.stringify(this));
5168 	debug("getRataDie: year is " +  years);
5169 	debug("getRataDie: day in year is " +  dayInYear);
5170 	debug("getRataDie: rdtime is " +  rdtime);
5171 	debug("getRataDie: rd is " +  (years + dayInYear + rdtime));
5172 	*/
5173 	
5174 	/**
5175 	 * @type {number|undefined} the RD number of this Gregorian date
5176 	 */
5177 	this.rd = years + dayInYear + rdtime;
5178 };
5179 
5180 /**
5181  * Return the rd number of the particular day of the week on or before the 
5182  * given rd. eg. The Sunday on or before the given rd.
5183  * @private
5184  * @param {number} rd the rata die date of the reference date
5185  * @param {number} dayOfWeek the day of the week that is being sought relative 
5186  * to the current date
5187  * @return {number} the rd of the day of the week
5188  */
5189 ilib.Date.GregRataDie.prototype._onOrBefore = function(rd, dayOfWeek) {
5190 	return rd - ilib.mod(Math.floor(rd) - dayOfWeek, 7);
5191 };
5192 
5193 /*
5194  * timezone.js - Definition of a time zone class
5195  * 
5196  * Copyright © 2012-2014, JEDLSoft
5197  *
5198  * Licensed under the Apache License, Version 2.0 (the "License");
5199  * you may not use this file except in compliance with the License.
5200  * You may obtain a copy of the License at
5201  *
5202  *     http://www.apache.org/licenses/LICENSE-2.0
5203  *
5204  * Unless required by applicable law or agreed to in writing, software
5205  * distributed under the License is distributed on an "AS IS" BASIS,
5206  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5207  *
5208  * See the License for the specific language governing permissions and
5209  * limitations under the License.
5210  */
5211 
5212 /*
5213 !depends 
5214 ilibglobal.js 
5215 locale.js
5216 localeinfo.js
5217 util/utils.js
5218 util/math.js
5219 calendar/gregratadie.js
5220 */
5221 
5222 // !data localeinfo zoneinfo
5223 
5224 /**
5225  * @class
5226  * Create a time zone instance. 
5227  * 
5228  * This class reports and transforms
5229  * information about particular time zones.<p>
5230  * 
5231  * The options parameter may contain any of the following properties:
5232  * 
5233  * <ul>
5234  * <li><i>id</i> - The id of the requested time zone such as "Europe/London" or 
5235  * "America/Los_Angeles". These are taken from the IANA time zone database. (See
5236  * http://www.iana.org/time-zones for more information.) <p>
5237  * 
5238  * There is one special 
5239  * time zone that is not taken from the IANA database called simply "local". In
5240  * this case, this class will attempt to discover the current time zone and
5241  * daylight savings time settings by calling standard Javascript classes to 
5242  * determine the offsets from UTC. 
5243  * 
5244  * <li><i>locale</i> - The locale for this time zone.
5245  * 
5246  * <li><i>offset</i> - Choose the time zone based on the offset from UTC given in
5247  * number of minutes (negative is west, positive is east).
5248  * 
5249  * <li><i>onLoad</i> - a callback function to call when the data is fully 
5250  * loaded. When the onLoad option is given, this class will attempt to
5251  * load any missing locale data using the ilib loader callback.
5252  * When the data is loaded, the onLoad function is called with the current 
5253  * instance as a parameter. 
5254  * 
5255  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
5256  * asynchronously. If this option is given as "false", then the "onLoad"
5257  * callback must be given, as the instance returned from this constructor will
5258  * not be usable for a while.
5259  *  
5260  * <li><i>loadParams</i> - an object containing parameters to pass to the 
5261  * loader callback function when locale data is missing. The parameters are not
5262  * interpretted or modified in any way. They are simply passed along. The object 
5263  * may contain any property/value pairs as long as the calling code is in
5264  * agreement with the loader callback function as to what those parameters mean.
5265  * </ul>
5266  * 
5267  * There is currently no way in the ECMAscript
5268  * standard to tell which exact time zone is currently in use. Choosing the
5269  * id "locale" or specifying an explicit offset will not give a specific time zone, 
5270  * as it is impossible to tell with certainty which zone the offsets 
5271  * match.<p>
5272  * 
5273  * When the id "local" is given or the offset option is specified, this class will
5274  * have the following behaviours:
5275  * <ul>
5276  * <li>The display name will always be given as the RFC822 style, no matter what
5277  * style is requested
5278  * <li>The id will also be returned as the RFC822 style display name
5279  * <li>When the offset is explicitly given, this class will assume the time zone 
5280  * does not support daylight savings time, and the offsets will be calculated 
5281  * the same way year round.
5282  * <li>When the offset is explicitly given, the inDaylightSavings() method will 
5283  * always return false.
5284  * <li>When the id "local" is given, this class will attempt to determine the 
5285  * daylight savings time settings by examining the offset from UTC on Jan 1
5286  * and June 1 of the current year. If they are different, this class assumes
5287  * that the local time zone uses DST. When the offset for a particular date is
5288  * requested, it will use the built-in Javascript support to determine the 
5289  * offset for that date.
5290  * </ul> 
5291  * 
5292  * If a more specific time zone is 
5293  * needed with display names and known start/stop times for DST, use the "id" 
5294  * property instead to specify the time zone exactly. You can perhaps ask the
5295  * user which time zone they prefer so that your app does not need to guess.<p>
5296  * 
5297  * If the id and the offset are both not given, the default time zone for the 
5298  * locale is retrieved from
5299  * the locale info. If the locale is not specified, the default locale for the
5300  * library is used.<p>
5301  * 
5302  * Because this class was designed for use in web sites, and the vast majority
5303  * of dates and times being formatted are recent date/times, this class is simplified
5304  * by not implementing historical time zones. That is, when governments change the 
5305  * time zone rules for a particular zone, only the latest such rule is implemented 
5306  * in this class. That means that determining the offset for a date that is prior 
5307  * to the last change may give the wrong result. Historical time zone calculations
5308  * may be implemented in a later version of iLib if there is enough demand for it,
5309  * but it would entail a much larger set of time zone data that would have to be
5310  * loaded.  
5311  * 
5312  * Depends directive: !depends timezone.js
5313  * 
5314  * @constructor
5315  * @param {Object} options Options guiding the construction of this time zone instance
5316  */
5317 ilib.TimeZone = function(options) {
5318 	this.sync = true;
5319 	this.locale = new ilib.Locale();
5320 	this.isLocal = false;
5321 	
5322 	if (options) {
5323 		if (options.locale) {
5324 			this.locale = (typeof(options.locale) === 'string') ? new ilib.Locale(options.locale) : options.locale;
5325 		}
5326 		
5327 		if (options.id) {
5328 			var id = options.id.toString();
5329 			if (id === 'local') {
5330 				this.isLocal = true;
5331 				
5332 				// use standard Javascript Date to figure out the time zone offsets
5333 				var now = new Date(), 
5334 					jan1 = new Date(now.getFullYear(), 0, 1),  // months in std JS Date object are 0-based
5335 					jun1 = new Date(now.getFullYear(), 5, 1);
5336 				
5337 				// Javascript's method returns the offset backwards, so we have to
5338 				// take the negative to get the correct offset
5339 				this.offsetJan1 = -jan1.getTimezoneOffset();
5340 				this.offsetJun1 = -jun1.getTimezoneOffset();
5341 				// the offset of the standard time for the time zone is always the one that is closest 
5342 				// to negative infinity of the two, no matter whether you are in the northern or southern 
5343 				// hemisphere, east or west
5344 				this.offset = Math.min(this.offsetJan1, this.offsetJun1);
5345 			}
5346 			this.id = id;
5347 		} else if (options.offset) {
5348 			this.offset = (typeof(options.offset) === 'string') ? parseInt(options.offset, 10) : options.offset;
5349 			this.id = this.getDisplayName(undefined, undefined);
5350 		}
5351 		
5352 		if (typeof(options.sync) !== 'undefined') {
5353 			this.sync = !!options.sync;
5354 		}
5355 		
5356 		this.loadParams = options.loadParams;
5357 		this.onLoad = options.onLoad;
5358 	}
5359 
5360 	//console.log("timezone: locale is " + this.locale);
5361 	
5362 	if (!this.id) {
5363 		new ilib.LocaleInfo(this.locale, {
5364 			sync: this.sync,
5365 			onLoad: ilib.bind(this, function (li) {
5366 				this.id = li.getTimeZone() || "Etc/UTC";
5367 				this._loadtzdata();
5368 			})
5369 		});
5370 	} else {
5371 		this._loadtzdata();
5372 	}
5373 
5374 	//console.log("localeinfo is: " + JSON.stringify(this.locinfo));
5375 	//console.log("id is: " + JSON.stringify(this.id));
5376 };
5377 
5378 /*
5379  * Explanation of the compressed time zone info properties.
5380  * {
5381  *     "o": "8:0",      // offset from UTC
5382  *     "f": "W{c}T",    // standard abbreviation. For time zones that observe DST, the {c} replacement is replaced with the 
5383  *                      // letter in the e.c or s.c properties below 
5384  *     "e": {           // info about the end of DST
5385  *         "j": 78322.5 // Julian day when the transition happens. Either specify the "j" property or all of the "m", "r", and 
5386  *                      // "t" properties, but not both sets.
5387  *         "m": 3,      // month that it ends
5388  *         "r": "l0",   // rule for the day it ends "l" = "last", numbers are Sun=0 through Sat=6. Other syntax is "0>7". 
5389  *                      // This means the 0-day (Sun) after the 7th of the month. Other possible operators are <, >, <=, >=
5390  *         "t": "2:0",  // time of day that the DST turns off, hours:minutes
5391  *         "c": "S"     // character to replace into the abbreviation for standard time 
5392  *     },
5393  *     "s": {           // info about the start of DST
5394  *         "j": 78189.5 // Julian day when the transition happens. Either specify the "j" property or all of the "m", "r", and 
5395  *                      // "t" properties, but not both sets.
5396  *         "m": 10,     // month that it starts
5397  *         "r": "l0",   // rule for the day it starts "l" = "last", numbers are Sun=0 through Sat=6. Other syntax is "0>7".
5398  *                      // This means the 0-day (Sun) after the 7th of the month. Other possible operators are <, >, <=, >=
5399  *         "t": "2:0",  // time of day that the DST turns on, hours:minutes
5400  *         "v": "1:0",  // amount of time saved in hours:minutes
5401  *         "c": "D"     // character to replace into the abbreviation for daylight time
5402  *     },
5403  *     "c": "AU",       // ISO code for the country that contains this time zone
5404  *     "n": "W. Australia {c} Time"
5405  *                      // long English name of the zone. The {c} replacement is for the word "Standard" or "Daylight" as appropriate
5406  * }
5407  */
5408 ilib.TimeZone.prototype._loadtzdata = function () {
5409 	// console.log("id is: " + JSON.stringify(this.id));
5410 	// console.log("zoneinfo is: " + JSON.stringify(ilib.data.zoneinfo[this.id]));
5411 	if (!ilib.data.zoneinfo[this.id] && typeof(this.offset) === 'undefined') {
5412 		ilib.loadData({
5413 			object: ilib.TimeZone, 
5414 			nonlocale: true,	// locale independent 
5415 			name: "zoneinfo/" + this.id + ".json", 
5416 			sync: this.sync, 
5417 			loadParams: this.loadParams, 
5418 			callback: ilib.bind(this, function (tzdata) {
5419 				if (tzdata && !ilib.isEmpty(tzdata)) {
5420 					ilib.data.zoneinfo[this.id] = tzdata;
5421 				}
5422 				this._initZone();
5423 			})
5424 		});
5425 	} else {
5426 		this._initZone();
5427 	}
5428 };
5429 
5430 ilib.TimeZone.prototype._initZone = function() {
5431 	/** 
5432 	 * @private
5433 	 * @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}} 
5434 	 */
5435 	this.zone = ilib.data.zoneinfo[this.id];
5436 	if (!this.zone && typeof(this.offset) === 'undefined') {
5437 		this.id = "Etc/UTC";
5438 		this.zone = ilib.data.zoneinfo[this.id];
5439 	}
5440 	
5441 	this._calcDSTSavings();
5442 	
5443 	if (typeof(this.offset) === 'undefined' && this.zone.o) {
5444 		var offsetParts = this._offsetStringToObj(this.zone.o);
5445 		/**
5446 		 * @private
5447 		 * @type {number} raw offset from UTC without DST, in minutes
5448 		 */
5449 		this.offset = (Math.abs(offsetParts.h || 0) * 60 + (offsetParts.m || 0)) * ilib.signum(offsetParts.h || 0);
5450 	}
5451 	
5452 	if (this.onLoad && typeof(this.onLoad) === 'function') {
5453 		this.onLoad(this);
5454 	}
5455 };
5456 
5457 ilib.data.timezone = {};
5458 
5459 /**
5460  * Return an array of available zone ids that the constructor knows about.
5461  * The country parameter is optional. If it is not given, all time zones will
5462  * be returned. If it specifies a country code, then only time zones for that
5463  * country will be returned.
5464  * 
5465  * @param {string} country country code for which time zones are being sought
5466  * @return {Array.<string>} an array of zone id strings
5467  */
5468 ilib.TimeZone.getAvailableIds = function (country) {
5469 	var tz, ids = [];
5470 	
5471 	if (!ilib.data.timezone.list) {
5472 		ilib.data.timezone.list = [];
5473 		if (ilib._load instanceof ilib.Loader) {
5474 			var hash = ilib._load.listAvailableFiles();
5475 			for (var dir in hash) {
5476 				var files = hash[dir];
5477 				if (typeof(files) === 'object' && files instanceof Array) {
5478 					files.forEach(function (filename) {
5479 						if (filename && filename.match(/^zoneinfo/)) {
5480 							ilib.data.timezone.list.push(filename.replace(/^zoneinfo\//, "").replace(/\.json$/, ""));
5481 						}
5482 					});
5483 				}
5484 			}
5485 		} else {
5486 			for (tz in ilib.data.zoneinfo) {
5487 				if (ilib.data.zoneinfo[tz]) {
5488 					ilib.data.timezone.list.push(tz);
5489 				}
5490 			}
5491 		}
5492 	}
5493 	
5494 	if (!country) {
5495 		// special zone meaning "the local time zone according to the JS engine we are running upon"
5496 		ids.push("local");
5497 		for (tz in ilib.data.timezone.list) {
5498 			if (ilib.data.timezone.list[tz]) {
5499 				ids.push(ilib.data.timezone.list[tz]);
5500 			}
5501 		}
5502 	} else {
5503 		if (!ilib.data.zoneinfo.zonetab) {
5504 			ilib.loadData({
5505 				object: ilib.TimeZone, 
5506 				nonlocale: true,	// locale independent 
5507 				name: "zoneinfo/zonetab.json", 
5508 				sync: true, 
5509 				callback: ilib.bind(this, function (tzdata) {
5510 					if (tzdata) {
5511 						ilib.data.zoneinfo.zonetab = tzdata;
5512 					}
5513 				})
5514 			});
5515 		}
5516 		ids = ilib.data.zoneinfo.zonetab[country];
5517 	}
5518 	
5519 	return ids;
5520 };
5521 
5522 /**
5523  * Return the id used to uniquely identify this time zone.
5524  * @return {string} a unique id for this time zone
5525  */
5526 ilib.TimeZone.prototype.getId = function () {
5527 	return this.id.toString();
5528 };
5529 
5530 /**
5531  * Return the abbreviation that is used for the current time zone on the given date.
5532  * The date may be in DST or during standard time, and many zone names have different
5533  * abbreviations depending on whether or not the date is falls within DST.<p>
5534  * 
5535  * There are two styles that are supported:
5536  * 
5537  * <ol>
5538  * <li>standard - returns the 3 to 5 letter abbreviation of the time zone name such 
5539  * as "CET" for "Central European Time" or "PDT" for "Pacific Daylight Time"
5540  * <li>rfc822 - returns an RFC 822 style time zone specifier, which specifies more
5541  * explicitly what the offset is from UTC
5542  * <li>long - returns the long name of the zone in English
5543  * </ol>
5544  *  
5545  * @param {ilib.Date=} date a date to determine if it is in daylight time or standard time
5546  * @param {string=} style one of "standard" or "rfc822". Default if not specified is "standard"
5547  * @return {string} the name of the time zone, abbreviated according to the style 
5548  */
5549 ilib.TimeZone.prototype.getDisplayName = function (date, style) {
5550 	style = (this.isLocal || typeof(this.zone) === 'undefined') ? "rfc822" : (style || "standard");
5551 	switch (style) {
5552 		default:
5553 		case 'standard':
5554 			if (this.zone.f && this.zone.f !== "zzz") {
5555 				if (this.zone.f.indexOf("{c}") !== -1) {
5556 					var letter = "";
5557 					letter = this.inDaylightTime(date) ? this.zone.s && this.zone.s.c : this.zone.e && this.zone.e.c; 
5558 					var temp = new ilib.String(this.zone.f);
5559 					return temp.format({c: letter || ""});
5560 				}
5561 				return this.zone.f;
5562 			} 
5563 			var temp = "GMT" + this.zone.o;
5564 			if (this.inDaylightTime(date)) {
5565 				temp += "+" + this.zone.s.v;
5566 			}
5567 			return temp;
5568 			break;
5569 		case 'rfc822':
5570 			var offset = this.getOffset(date), // includes the DST if applicable
5571 				ret = "UTC",
5572 				hour = offset.h || 0,
5573 				minute = offset.m || 0;
5574 			
5575 			if (hour !== 0) {
5576 				ret += (hour > 0) ? "+" : "-";
5577 				if (Math.abs(hour) < 10) {
5578 					ret += "0";
5579 				}
5580 				ret += (hour < 0) ? -hour : hour;
5581 				if (minute < 10) {
5582 					ret += "0";
5583 				}
5584 				ret += minute;
5585 			}
5586 			return ret; 
5587 		case 'long':
5588 			if (this.zone.n) {
5589 				if (this.zone.n.indexOf("{c}") !== -1) {
5590 					var str = this.inDaylightTime(date) ? "Daylight" : "Standard"; 
5591 					var temp = new ilib.String(this.zone.n);
5592 					return temp.format({c: str || ""});
5593 				}
5594 				return this.zone.n;
5595 			}
5596 			var temp = "GMT" + this.zone.o;
5597 			if (this.inDaylightTime(date)) {
5598 				temp += "+" + this.zone.s.v;
5599 			}
5600 			return temp;
5601 			break;
5602 	}
5603 };
5604 
5605 /**
5606  * Convert the offset string to an object with an h, m, and possibly s property
5607  * to indicate the hours, minutes, and seconds.
5608  * 
5609  * @private
5610  * @param {string} str the offset string to convert to an object
5611  * @return {Object.<{h:number,m:number,s:number}>} an object giving the offset for the zone at 
5612  * the given date/time, in hours, minutes, and seconds
5613  */
5614 ilib.TimeZone.prototype._offsetStringToObj = function (str) {
5615 	var offsetParts = (typeof(str) === 'string') ? str.split(":") : [],
5616 		ret = {h:0},
5617 		temp;
5618 	
5619 	if (offsetParts.length > 0) {
5620 		ret.h = parseInt(offsetParts[0], 10);
5621 		if (offsetParts.length > 1) {
5622 			temp = parseInt(offsetParts[1], 10);
5623 			if (temp) {
5624 				ret.m = temp;
5625 			}
5626 			if (offsetParts.length > 2) {
5627 				temp = parseInt(offsetParts[2], 10);
5628 				if (temp) {
5629 					ret.s = temp;
5630 				}
5631 			}
5632 		}
5633 	}
5634 
5635 	return ret;
5636 };
5637 
5638 /**
5639  * Returns the offset of this time zone from UTC at the given date/time. If daylight saving 
5640  * time is in effect at the given date/time, this method will return the offset value 
5641  * adjusted by the amount of daylight saving.
5642  * @param {ilib.Date=} date the date for which the offset is needed
5643  * @return {Object.<{h:number,m:number}>} an object giving the offset for the zone at 
5644  * the given date/time, in hours, minutes, and seconds  
5645  */
5646 ilib.TimeZone.prototype.getOffset = function (date) {
5647 	if (!date) {
5648 		return this.getRawOffset();
5649 	}
5650 	var offset = this.getOffsetMillis(date)/60000;
5651 	
5652 	var hours = ilib._roundFnc.down(offset/60),
5653 		minutes = Math.abs(offset) - Math.abs(hours)*60;
5654 
5655 	var ret = {
5656 		h: hours
5657 	};
5658 	if (minutes != 0) {
5659 		ret.m = minutes;
5660 	}
5661 	return ret;
5662 };
5663 
5664 /**
5665  * Returns the offset of this time zone from UTC at the given date/time expressed in 
5666  * milliseconds. If daylight saving 
5667  * time is in effect at the given date/time, this method will return the offset value 
5668  * adjusted by the amount of daylight saving. Negative numbers indicate offsets west
5669  * of UTC and conversely, positive numbers indicate offset east of UTC.
5670  *  
5671  * @param {ilib.Date=} date the date for which the offset is needed, or null for the
5672  * present date
5673  * @return {number} the number of milliseconds of offset from UTC that the given date is
5674  */
5675 ilib.TimeZone.prototype.getOffsetMillis = function (date) {
5676 	var ret;
5677 	
5678 	// check if the dst property is defined -- the intrinsic JS Date object doesn't work so
5679 	// well if we are in the overlap time at the end of DST
5680 	if (this.isLocal && typeof(date.dst) === 'undefined') {
5681 		var d = (!date) ? new Date() : new Date(date.getTimeExtended());
5682 		return -d.getTimezoneOffset() * 60000;
5683 	} 
5684 	
5685 	ret = this.offset;
5686 	
5687 	if (date && this.inDaylightTime(date)) {
5688 		ret += this.dstSavings;
5689 	}
5690 	
5691 	return ret * 60000;
5692 };
5693 
5694 /**
5695  * Return the offset in milliseconds when the date has an RD number in wall
5696  * time rather than in UTC time.
5697  * @protected
5698  * @param date the date to check in wall time
5699  * @returns {number} the number of milliseconds of offset from UTC that the given date is
5700  */
5701 ilib.TimeZone.prototype._getOffsetMillisWallTime = function (date) {
5702 	var ret;
5703 	
5704 	ret = this.offset;
5705 	
5706 	if (date && this.inDaylightTime(date, true)) {
5707 		ret += this.dstSavings;
5708 	}
5709 	
5710 	return ret * 60000;
5711 };
5712 
5713 /**
5714  * Returns the offset of this time zone from UTC at the given date/time. If daylight saving 
5715  * time is in effect at the given date/time, this method will return the offset value 
5716  * adjusted by the amount of daylight saving.
5717  * @param {ilib.Date=} date the date for which the offset is needed
5718  * @return {string} the offset for the zone at the given date/time as a string in the 
5719  * format "h:m:s" 
5720  */
5721 ilib.TimeZone.prototype.getOffsetStr = function (date) {
5722 	var offset = this.getOffset(date),
5723 		ret;
5724 	
5725 	ret = offset.h;
5726 	if (typeof(offset.m) !== 'undefined') {
5727 		ret += ":" + offset.m;
5728 		if (typeof(offset.s) !== 'undefined') {
5729 			ret += ":" + offset.s;
5730 		}
5731 	} else {
5732 		ret += ":0";
5733 	}
5734 	
5735 	return ret;
5736 };
5737 
5738 /**
5739  * Gets the offset from UTC for this time zone.
5740  * @return {Object.<{h:number,m:number,s:number}>} an object giving the offset from 
5741  * UTC for this time zone, in hours, minutes, and seconds 
5742  */
5743 ilib.TimeZone.prototype.getRawOffset = function () {
5744 	var hours = ilib._roundFnc.down(this.offset/60),
5745 		minutes = Math.abs(this.offset) - Math.abs(hours)*60;
5746 	
5747 	var ret = {
5748 		h: hours
5749 	};
5750 	if (minutes != 0) {
5751 		ret.m = minutes;
5752 	}
5753 	return ret;
5754 };
5755 
5756 /**
5757  * Gets the offset from UTC for this time zone expressed in milliseconds. Negative numbers
5758  * indicate zones west of UTC, and positive numbers indicate zones east of UTC.
5759  * 
5760  * @return {number} an number giving the offset from 
5761  * UTC for this time zone in milliseconds 
5762  */
5763 ilib.TimeZone.prototype.getRawOffsetMillis = function () {
5764 	return this.offset * 60000;
5765 };
5766 
5767 /**
5768  * Gets the offset from UTC for this time zone without DST savings.
5769  * @return {string} the offset from UTC for this time zone, in the format "h:m:s" 
5770  */
5771 ilib.TimeZone.prototype.getRawOffsetStr = function () {
5772 	var off = this.getRawOffset();
5773 	return off.h + ":" + (off.m || "0");
5774 };
5775 
5776 /**
5777  * Return the amount of time in hours:minutes that the clock is advanced during
5778  * daylight savings time.
5779  * @return {Object.<{h:number,m:number,s:number}>} the amount of time that the 
5780  * clock advances for DST in hours, minutes, and seconds 
5781  */
5782 ilib.TimeZone.prototype.getDSTSavings = function () {
5783 	if (this.isLocal) {
5784 		// take the absolute because the difference in the offsets may be positive or
5785 		// negative, depending on the hemisphere
5786 		var savings = Math.abs(this.offsetJan1 - this.offsetJun1);
5787 		var hours = ilib._roundFnc.down(savings/60),
5788 			minutes = savings - hours*60;
5789 		return {
5790 			h: hours,
5791 			m: minutes
5792 		};
5793 	} else if (this.zone && this.zone.s) {
5794 		return this._offsetStringToObj(this.zone.s.v);	// this.zone.start.savings
5795 	}
5796 	return {h:0};
5797 };
5798 
5799 /**
5800  * Return the amount of time in hours:minutes that the clock is advanced during
5801  * daylight savings time.
5802  * @return {string} the amount of time that the clock advances for DST in the
5803  * format "h:m:s"
5804  */
5805 ilib.TimeZone.prototype.getDSTSavingsStr = function () {
5806 	if (this.isLocal) {
5807 		var savings = this.getDSTSavings();
5808 		return savings.h + ":" + savings.m;
5809 	} else if (typeof(this.offset) !== 'undefined' && this.zone && this.zone.s) {
5810 		return this.zone.s.v;	// this.zone.start.savings
5811 	}
5812 	return "0:0";
5813 };
5814 
5815 /**
5816  * return the rd of the start of DST transition for the given year
5817  * @protected
5818  * @param {Object} rule set of rules
5819  * @param {number} year year to check
5820  * @return {number} the rd of the start of DST for the year
5821  */
5822 ilib.TimeZone.prototype._calcRuleStart = function (rule, year) {
5823 	var type = "=", 
5824 		weekday = 0, 
5825 		day, 
5826 		refDay, 
5827 		cal, 
5828 		hour = 0, 
5829 		minute = 0, 
5830 		second = 0,
5831 		time,
5832 		i;
5833 	
5834 	if (typeof(rule.j) !== 'undefined') {
5835 		refDay = new ilib.Date.GregRataDie({
5836 			julianday: rule.j
5837 		});
5838 	} else {
5839 		if (rule.r.charAt(0) == 'l' || rule.r.charAt(0) == 'f') {
5840 			cal = ilib.Cal.newInstance({type: "gregorian"});
5841 			type = rule.r.charAt(0);
5842 			weekday = parseInt(rule.r.substring(1), 10);
5843 			day = (type === 'l') ? cal.getMonLength(rule.m, year) : 1;
5844 			//console.log("_calcRuleStart: Calculating the " + 
5845 			//		(rule.r.charAt(0) == 'f' ? "first " : "last ") + weekday + 
5846 			//		" of month " + rule.m);
5847 		} else {
5848 			i = rule.r.indexOf('<');
5849 			if (i == -1) {
5850 				i = rule.r.indexOf('>');
5851 			}
5852 			
5853 			if (i != -1) {
5854 				type = rule.r.charAt(i);
5855 				weekday = parseInt(rule.r.substring(0, i), 10);
5856 				day = parseInt(rule.r.substring(i+1), 10); 
5857 				//console.log("_calcRuleStart: Calculating the " + weekday + 
5858 				//		type + day + " of month " + rule.m);
5859 			} else {
5860 				day = parseInt(rule.r, 10);
5861 				//console.log("_calcRuleStart: Calculating the " + day + " of month " + rule.m);
5862 			}
5863 		}
5864 	
5865 		if (rule.t) {
5866 			time = rule.t.split(":");
5867 			hour = parseInt(time[0], 10);
5868 			if (time.length > 1) {
5869 				minute = parseInt(time[1], 10);
5870 				if (time.length > 2) {
5871 					second = parseInt(time[2], 10);
5872 				}
5873 			}
5874 		}
5875 		//console.log("calculating rd of " + year + "/" + rule.m + "/" + day);
5876 		refDay = new ilib.Date.GregRataDie({
5877 			year: year, 
5878 			month: rule.m, 
5879 			day: day, 
5880 			hour: hour, 
5881 			minute: minute, 
5882 			second: second
5883 		});
5884 	}
5885 	//console.log("refDay is " + JSON.stringify(refDay));
5886 	var d = refDay.getRataDie();
5887 	
5888 	switch (type) {
5889 		case 'l':
5890 		case '<':
5891 			//console.log("returning " + refDay.onOrBefore(rd, weekday));
5892 			d = refDay.onOrBefore(weekday); 
5893 			break;
5894 		case 'f':
5895 		case '>':
5896 			//console.log("returning " + refDay.onOrAfterRd(rd, weekday));
5897 			d = refDay.onOrAfter(weekday); 
5898 			break;
5899 	}
5900 	return d;
5901 };
5902 
5903 /**
5904  * @private
5905  */
5906 ilib.TimeZone.prototype._calcDSTSavings = function () {
5907 	var saveParts = this.getDSTSavings();
5908 	
5909 	/**
5910 	 * @private
5911 	 * @type {number} savings in minutes when DST is in effect 
5912 	 */
5913 	this.dstSavings = (Math.abs(saveParts.h || 0) * 60 + (saveParts.m || 0)) * ilib.signum(saveParts.h || 0);
5914 };
5915 
5916 /**
5917  * @private
5918  */
5919 ilib.TimeZone.prototype._getDSTStartRule = function (year) {
5920 	// TODO: update this when historic/future zones are supported
5921 	return this.zone.s;
5922 };
5923 
5924 /**
5925  * @private
5926  */
5927 ilib.TimeZone.prototype._getDSTEndRule = function (year) {
5928 	// TODO: update this when historic/future zones are supported
5929 	return this.zone.e;
5930 };
5931 
5932 /**
5933  * Returns whether or not the given date is in daylight saving time for the current
5934  * zone. Note that daylight savings time is observed for the summer. Because
5935  * the seasons are reversed, daylight savings time in the southern hemisphere usually
5936  * runs from the end of the year through New Years into the first few months of the
5937  * next year. This method will correctly calculate the start and end of DST for any
5938  * location.
5939  * 
5940  * @param {ilib.Date=} date a date for which the info about daylight time is being sought,
5941  * or undefined to tell whether we are currently in daylight savings time
5942  * @param {boolean=} wallTime if true, then the given date is in wall time. If false or
5943  * undefined, it is in the usual UTC time.
5944  * @return {boolean} true if the given date is in DST for the current zone, and false
5945  * otherwise.
5946  */
5947 ilib.TimeZone.prototype.inDaylightTime = function (date, wallTime) {
5948 	var rd, startRd, endRd;
5949 
5950 	if (this.isLocal) {
5951 		// check if the dst property is defined -- the intrinsic JS Date object doesn't work so
5952 		// well if we are in the overlap time at the end of DST, so we have to work around that
5953 		// problem by adding in the savings ourselves
5954 		var offset = 0;
5955 		if (typeof(date.dst) !== 'undefined' && !date.dst) {
5956 			offset = this.dstSavings * 60000;
5957 		}
5958 		
5959 		var d = new Date(date ? date.getTimeExtended() + offset: undefined);
5960 		// the DST offset is always the one that is closest to positive infinity, no matter 
5961 		// if you are in the northern or southern hemisphere, east or west
5962 		var dst = Math.max(this.offsetJan1, this.offsetJun1);
5963 		return (-d.getTimezoneOffset() === dst);
5964 	}
5965 	
5966 	if (!date) {
5967 		date = new ilib.Date.GregDate(); // right now
5968 	} else if (!(date instanceof ilib.Date.GregDate)) {
5969 		// convert to Gregorian so that we can tell if it is in DST or not
5970 		date = new ilib.Date.GregDate({
5971 			julianday: date.getJulianDay(),
5972 			timezone: date.getTimeZone()
5973 		});
5974 	}
5975 	
5976 	// if we aren't using daylight time in this zone for the given year, then we are 
5977 	// not in daylight time
5978 	if (!this.useDaylightTime(date.year)) {
5979 		return false;
5980 	}
5981 	
5982 	// this should be a Gregorian RD number now, in UTC
5983 	rd = date.rd.getRataDie();
5984 	
5985 	// these calculate the start/end in local wall time
5986 	var startrule = this._getDSTStartRule(date.year);
5987 	var endrule = this._getDSTEndRule(date.year);
5988 	startRd = this._calcRuleStart(startrule, date.year);
5989 	endRd = this._calcRuleStart(endrule, date.year);
5990 	
5991 	if (wallTime) {
5992 		// rd is in wall time, so we have to make sure to skip the missing time
5993 		// at the start of DST when standard time ends and daylight time begins
5994 		startRd += this.dstSavings/1440;
5995 	} else {
5996 		// rd is in UTC, so we have to convert the start/end to UTC time so 
5997 		// that they can be compared directly to the UTC rd number of the date
5998 		
5999 		// when DST starts, time is standard time already, so we only have
6000 		// to subtract the offset to get to UTC and not worry about the DST savings
6001 		startRd -= this.offset/1440;  
6002 		
6003 		// when DST ends, time is in daylight time already, so we have to
6004 		// subtract the DST savings to get back to standard time, then the
6005 		// offset to get to UTC
6006 		endRd -= (this.offset + this.dstSavings)/1440;
6007 	}
6008 	
6009 	// In the northern hemisphere, the start comes first some time in spring (Feb-Apr), 
6010 	// then the end some time in the fall (Sept-Nov). In the southern
6011 	// hemisphere, it is the other way around because the seasons are reversed. Standard
6012 	// time is still in the winter, but the winter months are May-Aug, and daylight 
6013 	// savings time usually starts Aug-Oct of one year and runs through Mar-May of the 
6014 	// next year.
6015 	if (rd < endRd && endRd - rd <= this.dstSavings/1440 && typeof(date.dst) === 'boolean') {
6016 		// take care of the magic overlap time at the end of DST
6017 		return date.dst;
6018 	}
6019 	if (startRd < endRd) {
6020 		// northern hemisphere
6021 		return (rd >= startRd && rd < endRd) ? true : false;
6022 	} 
6023 	// southern hemisphere
6024 	return (rd >= startRd || rd < endRd) ? true : false;
6025 };
6026 
6027 /**
6028  * Returns true if this time zone switches to daylight savings time at some point
6029  * in the year, and false otherwise.
6030  * @param {number} year Whether or not the time zone uses daylight time in the given year. If
6031  * this parameter is not given, the current year is assumed.
6032  * @return {boolean} true if the time zone uses daylight savings time
6033  */
6034 ilib.TimeZone.prototype.useDaylightTime = function (year) {
6035 	
6036 	// this zone uses daylight savings time iff there is a rule defining when to start
6037 	// and when to stop the DST
6038 	return (this.isLocal && this.offsetJan1 !== this.offsetJun1) ||
6039 		(typeof(this.zone) !== 'undefined' && 
6040 		typeof(this.zone.s) !== 'undefined' && 
6041 		typeof(this.zone.e) !== 'undefined');
6042 };
6043 
6044 /**
6045  * Returns the ISO 3166 code of the country for which this time zone is defined.
6046  * @return {string} the ISO 3166 code of the country for this zone
6047  */
6048 ilib.TimeZone.prototype.getCountry = function () {
6049 	return this.zone.c;
6050 };
6051 /*
6052  * resources.js - Resource bundle definition
6053  * 
6054  * Copyright © 2012-2014, JEDLSoft
6055  *
6056  * Licensed under the Apache License, Version 2.0 (the "License");
6057  * you may not use this file except in compliance with the License.
6058  * You may obtain a copy of the License at
6059  *
6060  *     http://www.apache.org/licenses/LICENSE-2.0
6061  *
6062  * Unless required by applicable law or agreed to in writing, software
6063  * distributed under the License is distributed on an "AS IS" BASIS,
6064  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6065  *
6066  * See the License for the specific language governing permissions and
6067  * limitations under the License.
6068  */
6069 
6070 // !depends ilibglobal.js locale.js localeinfo.js strings.js util/utils.js
6071 
6072 // !data pseudomap
6073 
6074 /**
6075  * @class
6076  * Create a new resource bundle instance. The resource bundle loads strings
6077  * appropriate for a particular locale and provides them via the getString 
6078  * method.<p>
6079  * 
6080  * The options object may contain any (or none) of the following properties:
6081  * 
6082  * <ul>
6083  * <li><i>locale</i> - The locale of the strings to load. If not specified, the default
6084  * locale is the the default for the web page or app in which the bundle is 
6085  * being loaded.
6086  * 
6087  * <li><i>name</i> - Base name of the resource bundle to load. If not specified the default
6088  * base name is "resources".
6089  * 
6090  * <li><i>type</i> - Name the type of strings this bundle contains. Valid values are 
6091  * "xml", "html", "text", or "raw". The default is "text". If the type is "xml" or "html",
6092  * then XML/HTML entities and tags are not pseudo-translated. During a real translation, 
6093  * HTML character entities are translated to their corresponding characters in a source
6094  * string before looking that string up in the translations. Also, the characters "<", ">",
6095  * and "&" are converted to entities again in the output, but characters are left as they
6096  * are. If the type is "xml", "html", or "text" types, then the replacement parameter names
6097  * are not pseudo-translated as well so that the output can be used for formatting with 
6098  * the ilib.String class. If the type is raw, all characters are pseudo-translated, 
6099  * including replacement parameters as well as XML/HTML tags and entities.
6100  * 
6101  * <li><i>lengthen</i> - when pseudo-translating the string, tell whether or not to 
6102  * automatically lengthen the string to simulate "long" languages such as German
6103  * or French. This is a boolean value. Default is false.
6104  * 
6105  * <li><i>missing</i> - what to do when a resource is missing. The choices are:
6106  * <ul>
6107  *   <li><i>source</i> - return the source string unchanged
6108  *   <li><i>pseudo</i> - return the pseudo-translated source string, translated to the
6109  *   script of the locale if the mapping is available, or just the default Latin 
6110  *   pseudo-translation if not
6111  *   <li><i>empty</i> - return the empty string 
6112  * </ul>
6113  * The default behaviour is the same as before, which is to return the source string
6114  * unchanged.
6115  * 
6116  * <li><i>onLoad</i> - a callback function to call when the resources are fully 
6117  * loaded. When the onLoad option is given, this class will attempt to
6118  * load any missing locale data using the ilib loader callback.
6119  * When the constructor is done (even if the data is already preassembled), the 
6120  * onLoad function is called with the current instance as a parameter, so this
6121  * callback can be used with preassembled or dynamic loading or a mix of the two. 
6122  * 
6123  * <li>sync - tell whether to load any missing locale data synchronously or 
6124  * asynchronously. If this option is given as "false", then the "onLoad"
6125  * callback must be given, as the instance returned from this constructor will
6126  * not be usable for a while. 
6127  *
6128  * <li><i>loadParams</i> - an object containing parameters to pass to the 
6129  * loader callback function when locale data is missing. The parameters are not
6130  * interpretted or modified in any way. They are simply passed along. The object 
6131  * may contain any property/value pairs as long as the calling code is in
6132  * agreement with the loader callback function as to what those parameters mean.
6133  * </ul>
6134  * 
6135  * The locale option may be given as a locale spec string or as an 
6136  * ilib.Locale object. If the locale option is not specified, then strings for
6137  * the default locale will be loaded.<p> 
6138  * 
6139  * The name option can be used to put groups of strings together in a
6140  * single bundle. The strings will then appear together in a JS object in
6141  * a JS file that can be included before the ilib.<p>
6142  * 
6143  * A resource bundle with a particular name is actually a set of bundles
6144  * that are each specific to a language, a language plus a region, etc. 
6145  * All bundles with the same base name should
6146  * contain the same set of source strings, but with different translations for 
6147  * the given locale. The user of the bundle does not need to be aware of 
6148  * the locale of the bundle, as long as it contains values for the strings 
6149  * it needs.<p>
6150  * 
6151  * Strings in bundles for a particular locale are inherited from parent bundles
6152  * that are more generic. In general, the hierarchy is as follows (from 
6153  * least locale-specific to most locale-specific):
6154  * 
6155  * <ol>
6156  * <li> language
6157  * <li> region
6158  * <li> language_script
6159  * <li> language_region
6160  * <li> region_variant
6161  * <li> language_script_region
6162  * <li> language_region_variant
6163  * <li> language_script_region_variant
6164  * </ol>
6165  * 
6166  * That is, if the translation for a string does not exist in the current
6167  * locale, the more-generic parent locale is searched for the string. In the
6168  * worst case scenario, the string is not found in the base locale's strings. 
6169  * In this case, the missing option guides this class on what to do. If
6170  * the missing option is "source", then the original source is returned as 
6171  * the translation. If it is "empty", the empty string is returned. If it
6172  * is "pseudo", then the pseudo-translated string that is appropriate for
6173  * the default script of the locale is returned.<p> 
6174  * 
6175  * This allows developers to create code with new or changed strings in it and check in that
6176  * code without waiting for the translations to be done first. The translated
6177  * version of the app or web site will still function properly, but will show 
6178  * a spurious untranslated string here and there until the translations are 
6179  * done and also checked in.<p>   
6180  *  
6181  * The base is whatever language your developers use to code in. For
6182  * a German web site, strings in the source code may be written in German 
6183  * for example. Often this base is English, as many web sites are coded in
6184  * English, but that is not required.<p>
6185  * 
6186  * The strings can be extracted with the ilib localization tool (which will be
6187  * shipped at some future time.) Once the strings
6188  * have been translated, the set of translated files can be generated with the
6189  * same tool. The output from the tool can be used as input to the ResBundle
6190  * object. It is up to the web page or app to make sure the JS file that defines
6191  * the bundle is included before creating the ResBundle instance.<p>
6192  * 
6193  * A special locale "zxx-XX" is used as the pseudo-translation locale because
6194  * zxx means "no linguistic information" in the ISO 639 standard, and the region 
6195  * code XX is defined to be user-defined in the ISO 3166 standard. 
6196  * Pseudo-translation is a locale where the translations are generated on
6197  * the fly based on the contents of the source string. Characters in the source 
6198  * string are replaced with other characters and returned. 
6199  * 
6200  * Example. If the source string is:
6201  * 
6202  * <pre>
6203  * "This is a string"
6204  * </pre>
6205  * 
6206  * then the pseudo-translated version might look something like this: 
6207  * 
6208  * <pre>
6209  * "Ţħïş ïş á şţřïñĝ"
6210  * </pre>
6211  * <p>
6212  * 
6213  * Pseudo-translation can be used to test that your app or web site is translatable
6214  * before an actual translation has happened. These bugs can then be fixed 
6215  * before the translation starts, avoiding an explosion of bugs later when
6216  * each language's tester registers the same bug complaining that the same 
6217  * string is not translated. When pseudo-localizing with
6218  * the Latin script, this allows the strings to be readable in the UI in the 
6219  * source language (if somewhat funky-looking), 
6220  * so that a tester can easily verify that the string is properly externalized 
6221  * and loaded from a resource bundle without the need to be able to read a
6222  * foreign language.<p> 
6223  * 
6224  * If one of a list of script tags is given in the pseudo-locale specifier, then the
6225  * pseudo-localization can map characters to very rough transliterations of
6226  * characters in the given script. For example, zxx-Hebr-XX maps strings to
6227  * Hebrew characters, which can be used to test your UI in a right-to-left
6228  * language to catch bidi bugs before a translation is done. Currently, the
6229  * list of target scripts includes Hebrew (Hebr), Chinese Simplified Han (Hans),
6230  * and Cyrillic (Cyrl) with more to be added later. If no script is explicitly
6231  * specified in the locale spec, or if the script is not supported,
6232  * then the default mapping maps Latin base characters to accented versions of
6233  * those Latin characters as in the example above.
6234  *  
6235  * When the "lengthen" property is set to true in the options, the 
6236  * pseudotranslation code will add digits to the end of the string to simulate
6237  * the lengthening that occurs when translating to other languages. The above 
6238  * example will come out like this:
6239  * 
6240  * <pre>
6241  * "Ţħïş ïş á şţřïñĝ76543210"
6242  * </pre>
6243  * 
6244  * The string is lengthened according to the length of the source string. If
6245  * the source string is less than 20 characters long, the string is lengthened 
6246  * by 50%. If the source string is 20-40 
6247  * characters long, the string is lengthened by 33%. If te string is greater
6248  * than 40 characters long, the string is lengthened by 20%.<p>
6249  * 
6250  * The pseudotranslation always ends a string with the digit "0". If you do
6251  * not see the digit "0" in the UI for your app, you know that truncation
6252  * has occurred, and the number you see at the end of the string tells you 
6253  * how many characters were truncated.<p>
6254  * 
6255  * Depends directive: !depends resources.js
6256  * 
6257  * @constructor
6258  * @param {?Object} options Options controlling how the bundle is created
6259  */
6260 ilib.ResBundle = function (options) {
6261 	var lookupLocale, spec;
6262 	
6263 	this.locale = new ilib.Locale();	// use the default locale
6264 	this.baseName = "strings";
6265 	this.type = "text";
6266 	this.loadParams = {};
6267 	this.missing = "source";
6268 	this.sync = true;
6269 	
6270 	if (options) {
6271 		if (options.locale) {
6272 			this.locale = (typeof(options.locale) === 'string') ? 
6273 					new ilib.Locale(options.locale) :
6274 					options.locale;
6275 		}
6276 		if (options.name) {
6277 			this.baseName = options.name;
6278 		}
6279 		if (options.type) {
6280 			this.type = options.type;
6281 		}
6282 		this.lengthen = options.lengthen || false;
6283 		
6284 		if (typeof(options.sync) !== 'undefined') {
6285 			this.sync = (options.sync == true);
6286 		}
6287 		
6288 		if (typeof(options.loadParams) !== 'undefined') {
6289 			this.loadParams = options.loadParams;
6290 		}
6291 		if (typeof(options.missing) !== 'undefined') {
6292 			if (options.missing === "pseudo" || options.missing === "empty") {
6293 				this.missing = options.missing;
6294 			}
6295 		}
6296 	}
6297 	
6298 	this.map = {};
6299 
6300 	if (!ilib.ResBundle[this.baseName]) {
6301 		ilib.ResBundle[this.baseName] = {};
6302 	}
6303 
6304 	lookupLocale = this.locale.isPseudo() ? new ilib.Locale("en-US") : this.locale;
6305 
6306 	ilib.loadData({
6307 		object: ilib.ResBundle[this.baseName], 
6308 		locale: lookupLocale, 
6309 		name: this.baseName + ".json", 
6310 		sync: this.sync, 
6311 		loadParams: this.loadParams, 
6312 		callback: ilib.bind(this, function (map) {
6313 			if (!map) {
6314 				map = ilib.data[this.baseName] || {};
6315 				spec = lookupLocale.getSpec().replace(/-/g, '_');
6316 				ilib.ResBundle[this.baseName].cache[spec] = map;
6317 			}
6318 			this.map = map;
6319 			if (this.locale.isPseudo()) {
6320 				if (!ilib.ResBundle.pseudomap) {
6321 					ilib.ResBundle.pseudomap = {};
6322 				}
6323 	
6324 				this._loadPseudo(this.locale, options.onLoad);
6325 			} else if (this.missing === "pseudo") {
6326 				if (!ilib.ResBundle.pseudomap) {
6327 					ilib.ResBundle.pseudomap = {};
6328 				}
6329 	
6330 				new ilib.LocaleInfo(this.locale, {
6331 					sync: this.sync,
6332 					loadParams: this.loadParams,
6333 					onLoad: ilib.bind(this, function (li) {
6334 						var pseudoLocale = new ilib.Locale("zxx", "XX", undefined, li.getDefaultScript());
6335 						this._loadPseudo(pseudoLocale, options.onLoad);
6336 					})
6337 				});
6338 			} else {
6339 				if (options && typeof(options.onLoad) === 'function') {
6340 					options.onLoad(this);
6341 				}
6342 			}
6343 		})
6344 	});
6345 
6346 	// console.log("Merged resources " + this.locale.toString() + " are: " + JSON.stringify(this.map));
6347 	//if (!this.locale.isPseudo() && ilib.isEmpty(this.map)) {
6348 	//	console.log("Resources for bundle " + this.baseName + " locale " + this.locale.toString() + " are not available.");
6349 	//}
6350 };
6351 
6352 ilib.ResBundle.defaultPseudo = ilib.data.pseudomap || {
6353 	"a": "à",
6354 	"e": "ë",
6355 	"i": "í",
6356 	"o": "õ",
6357 	"u": "ü",
6358 	"y": "ÿ",
6359 	"A": "Ã",
6360 	"E": "Ë",
6361 	"I": "Ï",
6362 	"O": "Ø",
6363 	"U": "Ú",
6364 	"Y": "Ŷ"
6365 };
6366 
6367 ilib.ResBundle.prototype = {
6368     /**
6369      * @protected
6370      */
6371     _loadPseudo: function (pseudoLocale, onLoad) {
6372 		ilib.loadData({
6373 			object: ilib.ResBundle.pseudomap, 
6374 			locale: pseudoLocale, 
6375 			name: "pseudomap.json", 
6376 			sync: this.sync, 
6377 			loadParams: this.loadParams, 
6378 			callback: ilib.bind(this, function (map) {
6379 				if (!map || ilib.isEmpty(map)) {
6380 					map = ilib.ResBundle.defaultPseudo;
6381 					var spec = pseudoLocale.getSpec().replace(/-/g, '_');
6382 					ilib.ResBundle.pseudomap.cache[spec] = map;
6383 				}
6384 				this.pseudomap = map;
6385 				if (typeof(onLoad) === 'function') {
6386 					onLoad(this);
6387 				}	
6388 			})
6389 		});
6390     },
6391     
6392 	/**
6393 	 * Return the locale of this resource bundle.
6394 	 * @return {ilib.Locale} the locale of this resource bundle object 
6395 	 */
6396 	getLocale: function () {
6397 		return this.locale;
6398 	},
6399 	
6400 	/**
6401 	 * Return the name of this resource bundle. This corresponds to the name option
6402 	 * given to the constructor.
6403 	 * @return {string} name of the the current instance
6404 	 */
6405 	getName: function () {
6406 		return this.baseName;
6407 	},
6408 	
6409 	/**
6410 	 * Return the type of this resource bundle. This corresponds to the type option
6411 	 * given to the constructor.
6412 	 * @return {string} type of the the current instance
6413 	 */
6414 	getType: function () {
6415 		return this.type;
6416 	},
6417 
6418 	/*
6419 	 * @private
6420 	 * Pseudo-translate a string
6421 	 */
6422 	pseudo: function (str) {
6423 		if (!str) {
6424 			return undefined;
6425 		}
6426 		var ret = "", i;
6427 		for (i = 0; i < str.length; i++) {
6428 			if (this.type !== "raw") {
6429 				if (this.type === "html" || this.type === "xml") {
6430 					if (str.charAt(i) === '<') {
6431 						ret += str.charAt(i++);
6432 						while (i < str.length && str.charAt(i) !== '>') {
6433 							ret += str.charAt(i++);
6434 						}
6435 						if (i < str.length) {
6436 							ret += str.charAt(i++);
6437 						}
6438 					} else if (str.charAt(i) === '&') {
6439 						ret += str.charAt(i++);
6440 						while (i < str.length && str.charAt(i) !== ';' && str.charAt(i) !== ' ') {
6441 							ret += str.charAt(i++);
6442 						}
6443 						if (i < str.length) {
6444 							ret += str.charAt(i++);
6445 						}
6446 					}
6447 				}
6448 				if (i < str.length) { 
6449 					if (str.charAt(i) === '{') {
6450 						ret += str.charAt(i++);
6451 						while (i < str.length && str.charAt(i) !== '}') {
6452 							ret += str.charAt(i++);
6453 						}
6454 						if (i < str.length) {
6455 							ret += str.charAt(i);
6456 						}
6457 					} else {
6458 						ret += this.pseudomap[str.charAt(i)] || str.charAt(i);
6459 					}
6460 				}
6461 			} else {
6462 				ret += this.pseudomap[str.charAt(i)] || str.charAt(i);
6463 			}
6464 		}
6465 		if (this.lengthen) {
6466 			var add;
6467 			if (ret.length <= 20) {
6468 				add = Math.round(ret.length / 2);
6469 			} else if (ret.length > 20 && ret.length <= 40) {
6470 				add = Math.round(ret.length / 3);
6471 			} else {
6472 				add = Math.round(ret.length / 5);
6473 			}
6474 			for (i = add-1; i >= 0; i--) {
6475 				ret += (i % 10);
6476 			}
6477 		}
6478 		if (this.locale.getScript() === "Hans" || this.locale.getScript() === "Hant" ||
6479 				this.locale.getScript() === "Hani" ||
6480 				this.locale.getScript() === "Hrkt" || this.locale.getScript() === "Jpan" ||
6481 				this.locale.getScript() === "Hira" || this.locale.getScript() === "Kana" ) {
6482 			// simulate Asian languages by getting rid of all the spaces
6483 			ret = ret.replace(/ /g, "");
6484 		}
6485 		return ret;
6486 	},
6487 	
6488 	/*
6489 	 * @private
6490 	 * Escape html characters in the output.
6491 	 */
6492 	escapeXml: function (str) {
6493 		str = str.replace(/&/g, '&');
6494 		str = str.replace(/</g, '<');
6495 		str = str.replace(/>/g, '>');
6496 		return str;
6497 	},
6498 
6499 	/*
6500 	 * @private
6501 	 * @param {string} str the string to unescape
6502 	 */
6503 	unescapeXml: function (str) {
6504 		str = str.replace(/&/g, '&');
6505 		str = str.replace(/</g, '<');
6506 		str = str.replace(/>/g, '>');
6507 		return str;
6508 	},
6509 	
6510 	/*
6511 	 * @private
6512 	 * Create a key name out of a source string. All this does so far is 
6513 	 * compress sequences of white space into a single space on the assumption
6514 	 * that this doesn't really change the meaning of the string, and therefore
6515 	 * all such strings that compress to the same thing should share the same
6516 	 * translation.
6517 	 * @param {string} source the source string to make a key out of
6518 	 */
6519 	makeKey: function (source) {
6520 		var key = source.replace(/\s+/gm, ' ');
6521 		return (this.type === "xml" || this.type === "html") ? this.unescapeXml(key) : key;
6522 	},
6523 	
6524 	/**
6525 	 * Return a localized string. If the string is not found in the loaded set of
6526 	 * resources, the original source string is returned. If the key is not given,
6527 	 * then the source string itself is used as the key. In the case where the 
6528 	 * source string is used as the key, the whitespace is compressed down to 1 space
6529 	 * each, and the whitespace at the beginning and end of the string is trimmed.<p>
6530 	 * 
6531 	 * The escape mode specifies what type of output you are escaping the returned
6532 	 * string for. Modes are similar to the types: 
6533 	 * 
6534 	 * <ul>
6535 	 * <li>"html" -- prevents HTML injection by escaping the characters < > and &
6536 	 * <li>"xml" -- currently same as "html" mode
6537 	 * <li>"js" -- prevents breaking Javascript syntax by backslash escaping all quote and 
6538 	 * double-quote characters
6539 	 * <li>"attribute" -- meant for HTML attribute values. Currently this is the same as
6540 	 * "js" escape mode.
6541 	 * <li>"default" -- use the type parameter from the constructor as the escape mode as well
6542 	 * <li>"none" or undefined -- no escaping at all.
6543 	 * </ul>
6544 	 * 
6545 	 * The type parameter of the constructor specifies what type of strings this bundle
6546 	 * is operating upon. This allows pseudo-translation and automatic key generation
6547 	 * to happen properly by telling this class how to parse the string. The escape mode 
6548 	 * for this method is different in that it specifies how this string will be used in 
6549 	 * the calling code and therefore how to escape it properly.<p> 
6550 	 * 
6551 	 * For example, a section of Javascript code may be constructing an HTML snippet in a 
6552 	 * string to add to the web page. In this case, the type parameter in the constructor should
6553 	 * be "html" so that the source string can be parsed properly, but the escape mode should
6554 	 * be "js" so that the output string can be used in Javascript without causing syntax
6555 	 * errors.
6556 	 * 
6557 	 * @param {?string=} source the source string to translate
6558 	 * @param {?string=} key optional name of the key, if any
6559 	 * @param {?string=} escapeMode escape mode, if any
6560 	 * @return {ilib.String|undefined} the translation of the given source/key or undefined 
6561 	 * if the translation is not found and the source is undefined 
6562 	 */
6563 	getString: function (source, key, escapeMode) {
6564 		if (!source && !key) return new ilib.String("");
6565 
6566 		var trans;
6567 		if (this.locale.isPseudo()) {
6568 			var str = source ? source : this.map[key];
6569 			trans = this.pseudo(str || key);
6570 		} else {
6571 			var keyName = key || this.makeKey(source);
6572 			if (typeof(this.map[keyName]) !== 'undefined') {
6573 				trans = this.map[keyName];
6574 			} else if (this.missing === "pseudo") {
6575 				trans = this.pseudo(source || key);
6576 			} else if (this.missing === "empty") {
6577 				trans = "";
6578 			} else {
6579 				trans = source;
6580 			}
6581 		}
6582 
6583 		if (escapeMode && escapeMode !== "none") {
6584 			if (escapeMode == "default") {
6585 				escapeMode = this.type;
6586 			}
6587 			if (escapeMode === "xml" || escapeMode === "html") {
6588 				trans = this.escapeXml(trans);
6589 			} else if (escapeMode == "js" || escapeMode === "attribute") {
6590 				trans = trans.replace(/'/g, "\\\'").replace(/"/g, "\\\"");
6591 			}
6592 		}
6593 		if (trans === undefined) {
6594 			return undefined;
6595 		} else {
6596 			var ret = new ilib.String(trans);
6597 			ret.setLocale(this.locale.getSpec(), true, this.loadParams); // no callback
6598 			return ret;
6599 		}
6600 	},
6601 	
6602 	/**
6603 	 * Return a localized string as a Javascript object. This does the same thing as
6604 	 * the getString() method, but it returns a regular Javascript string instead of
6605 	 * and ilib.String instance. This means it cannot be formatted with the format()
6606 	 * method without being wrapped in an ilib.String instance first.
6607 	 * 
6608 	 * @param {?string=} source the source string to translate
6609 	 * @param {?string=} key optional name of the key, if any
6610 	 * @param {?string=} escapeMode escape mode, if any
6611 	 * @return {string|undefined} the translation of the given source/key or undefined 
6612 	 * if the translation is not found and the source is undefined
6613 	 */
6614 	getStringJS: function(source, key, escapeMode) {
6615 		return this.getString(source, key, escapeMode).toString();
6616 	},
6617 	
6618 	/**
6619 	 * Return true if the current bundle contains a translation for the given key and
6620 	 * source. The
6621 	 * getString method will always return a string for any given key and source 
6622 	 * combination, so it cannot be used to tell if a translation exists. Either one
6623 	 * or both of the source and key must be specified. If both are not specified,
6624 	 * this method will return false.
6625 	 * 
6626 	 * @param {?string=} source source string to look up
6627 	 * @param {?string=} key key to look up
6628 	 * @return {boolean} true if this bundle contains a translation for the key, and 
6629 	 * false otherwise
6630 	 */
6631 	containsKey: function(source, key) {
6632 		if (typeof(source) === 'undefined' && typeof(key) === 'undefined') {
6633 			return false;
6634 		}
6635 		
6636 		var keyName = key || this.makeKey(source);
6637 		return typeof(this.map[keyName]) !== 'undefined';
6638 	},
6639 	
6640 	/**
6641 	 * Return the merged resources as an entire object. When loading resources for a
6642 	 * locale that are not just a set of translated strings, but instead an entire 
6643 	 * structured javascript object, you can gain access to that object via this call. This method
6644 	 * will ensure that all the of the parts of the object are correct for the locale.<p>
6645 	 * 
6646 	 * For pre-assembled data, it starts by loading <i>ilib.data[name]</i>, where 
6647 	 * <i>name</i> is the base name for this set of resources. Then, it successively 
6648 	 * merges objects in the base data using progressively more locale-specific data. 
6649 	 * It loads it in this order from <i>ilib.data</i>:
6650 	 * 
6651 	 * <ol>
6652 	 * <li> language
6653 	 * <li> region
6654 	 * <li> language_script
6655 	 * <li> language_region
6656 	 * <li> region_variant
6657 	 * <li> language_script_region
6658 	 * <li> language_region_variant
6659 	 * <li> language_script_region_variant
6660 	 * </ol>
6661 	 * 
6662 	 * For dynamically loaded data, the code attempts to load the same sequence as
6663 	 * above, but with slash path separators instead of underscores.<p>
6664 	 *  
6665 	 * Loading the resources this way allows the program to share resources between all
6666 	 * locales that share a common language, region, or script. As a 
6667 	 * general rule-of-thumb, resources should be as generic as possible in order to
6668 	 * cover as many locales as possible.
6669 	 * 
6670 	 * @return {Object} returns the object that is the basis for this resources instance
6671 	 */
6672 	getResObj: function () {
6673 		return this.map;
6674 	}
6675 };
6676 
6677 /*
6678  * util/jsutils.js - Misc utilities to work around Javascript engine differences
6679  * 
6680  * Copyright © 2013-2014, JEDLSoft
6681  *
6682  * Licensed under the Apache License, Version 2.0 (the "License");
6683  * you may not use this file except in compliance with the License.
6684  * You may obtain a copy of the License at
6685  *
6686  *     http://www.apache.org/licenses/LICENSE-2.0
6687  *
6688  * Unless required by applicable law or agreed to in writing, software
6689  * distributed under the License is distributed on an "AS IS" BASIS,
6690  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6691  *
6692  * See the License for the specific language governing permissions and
6693  * limitations under the License.
6694  */
6695 
6696 // !depends ilibglobal.js
6697 
6698 /**
6699  * Perform a shallow copy of the source object to the target object. This only 
6700  * copies the assignments of the source properties to the target properties, 
6701  * but not recursively from there.<p>
6702  * 
6703  * Depends directive: !depends utils.js
6704  * 
6705  * @static
6706  * @param {Object} source the source object to copy properties from
6707  * @param {Object} target the target object to copy properties into
6708  */
6709 ilib.shallowCopy = function (source, target) {
6710 	var prop = undefined;
6711 	if (source && target) {
6712 		for (prop in source) {
6713 			if (prop !== undefined && typeof(source[prop]) !== 'undefined') {
6714 				target[prop] = source[prop];
6715 			}
6716 		}
6717 	}
6718 };
6719 
6720 /** [Need Comment]
6721  * 
6722  */
6723 ilib.deepCopy = function(from, to) {
6724 	var prop;
6725 
6726 	for (prop in from) {
6727 		if (prop) {
6728 			if (typeof(from[prop]) === 'object') {
6729 				to[prop] ={};
6730 				ilib.deepCopy(from[prop], to[prop]);
6731 			} else {
6732 				to[prop] = from[prop];
6733 			}
6734 		}
6735 	}
6736 	return to;
6737 };
6738 
6739 /**
6740  * Map a string to the given set of alternate characters. If the target set
6741  * does not contain a particular character in the input string, then that
6742  * character will be copied to the output unmapped.
6743  * 
6744  * @static
6745  * @param {string} str a string to map to an alternate set of characters
6746  * @param {Array.<string>|Object} map a mapping to alternate characters
6747  * @return {string} the source string where each character is mapped to alternate characters
6748  */
6749 ilib.mapString = function (str, map) {
6750 	var mapped = "";
6751 	if (map && str) {
6752 		for (var i = 0; i < str.length; i++) {
6753 			var c = str.charAt(i); // TODO use a char iterator?
6754 			mapped += map[c] || c; 
6755 		}
6756 	} else {
6757 		mapped = str;
6758 	}
6759 	return mapped;
6760 };
6761 
6762 /**
6763  * Check if an object is a member of the given array. If this javascript engine
6764  * support indexOf, it is used directly. Otherwise, this function implements it
6765  * itself. The idea is to make sure that you can use the quick indexOf if it is
6766  * available, but use a slower implementation in older engines as well.
6767  * 
6768  * @static
6769  * @param {Array.<Object>} array array to search
6770  * @param {Object} obj object being sought. This should be of the same type as the
6771  * members of the array being searched. If not, this function will not return
6772  * any results.
6773  * @return {number} index of the object in the array, or -1 if it is not in the array.
6774  */
6775 ilib.indexOf = function(array, obj) {
6776 	if (!array || !obj) {
6777 		return -1;
6778 	}
6779 	if (typeof(array.indexOf) === 'function') {
6780 		return array.indexOf(obj);
6781 	} else {
6782 		for (var i = 0; i < array.length; i++) {
6783 	        if (array[i] === obj) {
6784 	            return i;
6785 	        }
6786 	    }
6787 	    return -1;
6788 	}
6789 };
6790 
6791 /**
6792  * @static
6793  * Convert a string into the hexadecimal representation
6794  * of the Unicode characters in that string.
6795  * 
6796  * @param {string} string The string to convert
6797  * @param {number=} limit the number of digits to use to represent the character (1 to 8)
6798  * @return {string} a hexadecimal representation of the
6799  * Unicode characters in the input string
6800  */
6801 ilib.toHexString = function(string, limit) {
6802 	var i, 
6803 		result = "", 
6804 		lim = (limit && limit < 9) ? limit : 4;
6805 	
6806 	if (!string) {
6807 		return "";
6808 	}
6809 	for (i = 0; i < string.length; i++) {
6810 		var ch = string.charCodeAt(i).toString(16);
6811 		result += "00000000".substring(0, lim-ch.length) + ch;
6812 	}
6813 	return result.toUpperCase();
6814 };
6815 
6816 /*
6817  * datefmt.js - Date formatter definition
6818  * 
6819  * Copyright © 2012-2014, JEDLSoft
6820  *
6821  * Licensed under the Apache License, Version 2.0 (the "License");
6822  * you may not use this file except in compliance with the License.
6823  * You may obtain a copy of the License at
6824  *
6825  *     http://www.apache.org/licenses/LICENSE-2.0
6826  *
6827  * Unless required by applicable law or agreed to in writing, software
6828  * distributed under the License is distributed on an "AS IS" BASIS,
6829  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6830  *
6831  * See the License for the specific language governing permissions and
6832  * limitations under the License.
6833  */
6834 
6835 /*
6836 !depends 
6837 ilibglobal.js 
6838 locale.js 
6839 date.js 
6840 strings.js 
6841 resources.js 
6842 calendar.js
6843 localeinfo.js
6844 timezone.js
6845 calendar/gregorian.js
6846 util/jsutils.js
6847 */
6848 
6849 // !data dateformats sysres
6850 
6851 /**
6852  * @class
6853  * Create a new date formatter instance. The date formatter is immutable once
6854  * it is created, but can format as many different dates as needed with the same
6855  * options. Create different date formatter instances for different purposes
6856  * and then keep them cached for use later if you have more than one date to
6857  * format.<p>
6858  * 
6859  * The options may contain any of the following properties:
6860  * 
6861  * <ul>
6862  * <li><i>locale</i> - locale to use when formatting the date/time. If the locale is
6863  * not specified, then the default locale of the app or web page will be used.
6864  * 
6865  * <li><i>calendar</i> - the type of calendar to use for this format. The value should
6866  * be a sting containing the name of the calendar. Currently, the supported
6867  * types are "gregorian", "julian", "arabic", "hebrew", or "chinese". If the
6868  * calendar is not specified, then the default calendar for the locale is used. When the
6869  * calendar type is specified, then the format method must be called with an instance of
6870  * the appropriate date type. (eg. Gregorian calendar means that the format method must 
6871  * be called with a GregDate instance.)
6872  *  
6873  * <li><i>timezone</i> - time zone to use when formatting times. This may be a time zone
6874  * instance or a time zone specifier from the IANA list of time zone database names 
6875  * (eg. "America/Los_Angeles"), 
6876  * the string "local", or a string specifying the offset in RFC 822 format. The IANA
6877  * list of time zone names can be viewed at 
6878  * <a href="http://en.wikipedia.org/wiki/List_of_tz_database_time_zones">this page</a>.
6879  * If the time zone is given as "local", the offset from UTC as given by
6880  * the Javascript system is used. If the offset is given as an RFC 822 style offset
6881  * specifier, it will parse that string and use the resulting offset. If the time zone
6882  * is not specified, the
6883  * default time zone for the locale is used. If both the date object and this formatter
6884  * instance contain time zones and those time zones are different from each other, the 
6885  * formatter will calculate the offset between the time zones and subtract it from the 
6886  * date before formatting the result for the current time zone. The theory is that a date
6887  * object that contains a time zone specifies a specific instant in time that is valid
6888  * around the world, whereas a date object without one is a local time and can only be
6889  * used for doing things in the local time zone of the user.
6890  * 
6891  * <li><i>type</i> - Specify whether this formatter should format times only, dates only, or
6892  * both times and dates together. Valid values are "time", "date", and "datetime". Note that
6893  * in some locales, the standard format uses the order "time followed by date" and in others, 
6894  * the order is exactly opposite, so it is better to create a single "datetime" formatter 
6895  * than it is to create a time formatter and a date formatter separately and concatenate the 
6896  * results. A "datetime" formatter will get the order correct for the locale.<p>
6897  * 
6898  * The default type if none is specified in with the type option is "date".
6899  * 
6900  * <li><i>length</i> - Specify the length of the format to use. The length is the approximate size of the 
6901  * formatted string.
6902  * 
6903  * <ul>
6904  * <li><i>short</i> - use a short representation of the time. This is the most compact format possible for the locale.
6905  * <li><i>medium</i> - use a medium length representation of the time. This is a slightly longer format.
6906  * <li><i>long</i> - use a long representation of the time. This is a fully specified format, but some of the textual 
6907  * components may still be abbreviated
6908  * <li><i>full</i> - use a full representation of the time. This is a fully specified format where all the textual 
6909  * components are spelled out completely
6910  * </ul>
6911  * 
6912  * 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
6913  * format, the month name is textual instead of numeric and is longer, the year is 4 digits instead of 2, and the format 
6914  * contains slightly more spaces and formatting characters.<p>
6915  * 
6916  * Note that the length parameter does not specify which components are to be formatted. Use the "date" and the "time"
6917  * properties to specify the components. Also, very few of the components of a time format differ according to the length,
6918  * so this property has little to no affect on time formatting.
6919  * 
6920  * <li><i>date</i> - This property tells
6921  * which components of a date format to use. For example,
6922  * sometimes you may wish to format a date that only contains the month and date
6923  * without the year, such as when displaying a person's yearly birthday. The value
6924  * of this property allows you to specify only those components you want to see in the
6925  * final output, ordered correctly for the locale. <p>
6926  * 
6927  * Valid values are:
6928  * 
6929  * <ul>
6930  * <li><i>dmwy</i> - format all components, weekday, date, month, and year
6931  * <li><i>dmy</i> - format only date, month, and year
6932  * <li><i>dmw</i> - format only weekday, date, and month
6933  * <li><i>dm</i> - format only date and month
6934  * <li><i>my</i> - format only month and year
6935  * <li><i>dw</i> - format only the weekday and date
6936  * <li><i>d</i> - format only the date
6937  * <li><i>m</i> - format only the month, in numbers for shorter lengths, and letters for 
6938  * longer lengths
6939  * <li><i>n</i> - format only the month, in letters only for all lengths
6940  * <li><i>y</i> - format only the year
6941  * </ul>
6942  * Default components, if this property is not specified, is "dmy". This property may be specified
6943  * but has no affect if the current formatter is for times only.
6944  * 
6945  * <li><i>time</i> - This property gives which components of a time format to use. The time will be formatted 
6946  * correctly for the locale with only the time components requested. For example, a clock might only display 
6947  * the hour and minute and not need the seconds or the am/pm component. In this case, the time property should be set 
6948  * to "hm". <p>
6949  * 
6950  * Valid values for this property are:
6951  * 
6952  * <ul>
6953  * <li><i>ahmsz</i> - format the hours, minutes, seconds, am/pm (if using a 12 hour clock), and the time zone
6954  * <li><i>ahms</i> - format the hours, minutes, seconds, and am/pm (if using a 12 hour clock)
6955  * <li><i>hmsz</i> - format the hours, minutes, seconds, and the time zone
6956  * <li><i>hms</i> - format the hours, minutes, and seconds
6957  * <li><i>ahmz</i> - format the hours, minutes, am/pm (if using a 12 hour clock), and the time zone
6958  * <li><i>ahm</i> - format the hours, minutes, and am/pm (if using a 12 hour clock)
6959  * <li><i>hmz</i> - format the hours, minutes, and the time zone
6960  * <li><i>ah</i> - format only the hours and am/pm if using a 12 hour clock
6961  * <li><i>hm</i> - format only the hours and minutes
6962  * <li><i>ms</i> - format only the minutes and seconds
6963  * <li><i>h</i> - format only the hours
6964  * <li><i>m</i> - format only the minutes
6965  * <li><i>s</i> - format only the seconds
6966  * </ul>
6967  * 
6968  * If you want to format a length of time instead of a particular instant
6969  * in time, use the duration formatter object (ilib.DurFmt) instead because this
6970  * formatter is geared towards instants. A date formatter will make sure that each component of the 
6971  * time is within the normal range
6972  * for that component. That is, the minutes will always be between 0 and 59, no matter
6973  * what is specified in the date to format. A duration format will allow the number
6974  * of minutes to exceed 59 if, for example, you were displaying the length of
6975  * a movie of 198 minutes.<p>
6976  * 
6977  * Default value if this property is not specified is "hma".
6978  * 
6979  * <li><i>clock</i> - specify that the time formatter should use a 12 or 24 hour clock. 
6980  * Valid values are "12" and "24".<p>
6981  * 
6982  * In some locales, both clocks are used. For example, in en_US, the general populace uses
6983  * a 12 hour clock with am/pm, but in the US military or in nautical or aeronautical or 
6984  * scientific writing, it is more common to use a 24 hour clock. This property allows you to
6985  * construct a formatter that overrides the default for the locale.<p>
6986  * 
6987  * If this property is not specified, the default is to use the most widely used convention
6988  * for the locale.
6989  *  
6990  * <li><i>template</i> - use the given template string as a fixed format when formatting 
6991  * the date/time. Valid codes to use in a template string are as follows:
6992  * 
6993  * <ul>
6994  * <li><i>a</i> - am/pm marker
6995  * <li><i>d</i> - 1 or 2 digit date of month, not padded
6996  * <li><i>dd</i> - 1 or 2 digit date of month, 0 padded to 2 digits
6997  * <li><i>O</i> - ordinal representation of the date of month (eg. "1st", "2nd", etc.)
6998  * <li><i>D</i> - 1 to 3 digit day of year
6999  * <li><i>DD</i> - 1 to 3 digit day of year, 0 padded to 2 digits
7000  * <li><i>DDD</i> - 1 to 3 digit day of year, 0 padded to 3 digits
7001  * <li><i>M</i> - 1 or 2 digit month number, not padded
7002  * <li><i>MM</i> - 1 or 2 digit month number, 0 padded to 2 digits
7003  * <li><i>N</i> - 1 character month name abbreviation
7004  * <li><i>NN</i> - 2 character month name abbreviation
7005  * <li><i>MMM</i> - 3 character month month name abbreviation
7006  * <li><i>MMMM</i> - fully spelled out month name
7007  * <li><i>yy</i> - 2 digit year
7008  * <li><i>yyyy</i> - 4 digit year
7009  * <li><i>E</i> - day-of-week name, abbreviated to a single character
7010  * <li><i>EE</i> - day-of-week name, abbreviated to a max of 2 characters
7011  * <li><i>EEE</i> - day-of-week name, abbreviated to a max of 3 characters
7012  * <li><i>EEEE</i> - day-of-week name fully spelled out 
7013  * <li><i>G</i> - era designator
7014  * <li><i>w</i> - week number in year
7015  * <li><i>ww</i> - week number in year, 0 padded to 2 digits
7016  * <li><i>W</i> - week in month
7017  * <li><i>h</i> - hour (12 followed by 1 to 11)
7018  * <li><i>hh</i> - hour (12, followed by 1 to 11), 0 padded to 2 digits
7019  * <li><i>k</i> - hour (1 to 24)
7020  * <li><i>kk</i> - hour (1 to 24), 0 padded to 2 digits
7021  * <li><i>H</i> - hour (0 to 23)
7022  * <li><i>HH</i> - hour (0 to 23), 0 padded to 2 digits
7023  * <li><i>K</i> - hour (0 to 11)
7024  * <li><i>KK</i> - hour (0 to 11), 0 padded to 2 digits
7025  * <li><i>m</i> - minute in hour
7026  * <li><i>mm</i> - minute in hour, 0 padded to 2 digits
7027  * <li><i>s</i> - second in minute
7028  * <li><i>ss</i> - second in minute, 0 padded to 2 digits
7029  * <li><i>S</i> - millisecond (1 to 3 digits)
7030  * <li><i>SSS</i> - millisecond, 0 padded to 3 digits
7031  * <li><i>z</i> - general time zone
7032  * <li><i>Z</i> - RFC 822 time zone
7033  * </ul>
7034  * 
7035  * <li><i>useNative</i> - the flag used to determine whether to use the native script settings 
7036  * for formatting the numbers.
7037  *
7038  * <li><i>meridiems</i> - string that specifies what style of meridiems to use with this 
7039  * format. The choices are "default", "gregorian", "ethiopic", and "chinese". The "default" 
7040  * style is often the simple Gregorian AM/PM, but the actual style is chosen by the locale. 
7041  * (For almost all locales, the Gregorian AM/PM style is most frequently used.)
7042  * The "ethiopic" style uses 5 different meridiems for "morning", "noon", "afternoon", 
7043  * "evening", and "night". The "chinese" style uses 7 different meridiems corresponding 
7044  * to the various parts of the day. N.B. Even for the Chinese locales, the default is "gregorian"
7045  * when formatting dates in the Gregorian calendar.
7046  *
7047  * <li><i>onLoad</i> - a callback function to call when the date format object is fully 
7048  * loaded. When the onLoad option is given, the DateFmt object will attempt to
7049  * load any missing locale data using the ilib loader callback.
7050  * When the constructor is done (even if the data is already preassembled), the 
7051  * onLoad function is called with the current instance as a parameter, so this
7052  * callback can be used with preassembled or dynamic loading or a mix of the two.
7053  * 
7054  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
7055  * asynchronously. If this option is given as "false", then the "onLoad"
7056  * callback must be given, as the instance returned from this constructor will
7057  * not be usable for a while.
7058  *  
7059  * <li><i>loadParams</i> - an object containing parameters to pass to the 
7060  * loader callback function when locale data is missing. The parameters are not
7061  * interpretted or modified in any way. They are simply passed along. The object 
7062  * may contain any property/value pairs as long as the calling code is in
7063  * agreement with the loader callback function as to what those parameters mean.
7064  * </ul>
7065  * 
7066  * Any substring containing letters within single or double quotes will be used 
7067  * as-is in the final output and will not be interpretted for codes as above.<p>
7068  * 
7069  * Example: a date format in Spanish might be given as: "'El' d. 'de' MMMM", where
7070  * the 'El' and the 'de' are left as-is in the output because they are quoted. Typical 
7071  * output for this example template might be, "El 5. de Mayo".
7072  * 
7073  * The following options will be used when formatting a date/time with an explicit
7074  * template:
7075  * 
7076  * <ul>
7077  * <li>locale - the locale is only used for 
7078  * translations of things like month names or day-of-week names.
7079  * <li>calendar - used to translate a date instance into date/time component values 
7080  * that can be formatted into the template
7081  * <li>timezone - used to figure out the offset to add or subtract from the time to
7082  * get the final time component values
7083  * <li>clock - used to figure out whether to format times with a 12 or 24 hour clock.
7084  * If this option is specified, it will override the hours portion of a time format.
7085  * That is, "hh" is switched with "HH" and "kk" is switched with "KK" as appropriate. 
7086  * If this option is not specified, the 12/24 code in the template will dictate whether 
7087  * to use the 12 or 24 clock, and the 12/24 default in the locale will be ignored.
7088  * </ul>
7089  * 
7090  * All other options will be ignored and their corresponding getter methods will
7091  * return the empty string.<p>
7092  * 
7093  * Depends directive: !depends datefmt.js
7094  * 
7095  * @constructor
7096  * @param {Object} options options governing the way this date formatter instance works
7097  */
7098 ilib.DateFmt = function(options) {
7099 	var arr, i, bad, 
7100 		sync = true, 
7101 		loadParams = undefined;
7102 	
7103 	this.locale = new ilib.Locale();
7104 	this.type = "date";
7105 	this.length = "s";
7106 	this.dateComponents = "dmy";
7107 	this.timeComponents = "ahm";
7108 	this.meridiems = "default";
7109 	
7110 	if (options) {
7111 		if (options.locale) {
7112 			this.locale = (typeof(options.locale) === 'string') ? new ilib.Locale(options.locale) : options.locale;
7113 		}
7114 		
7115 		if (options.type) {
7116 			if (options.type === 'date' || options.type === 'time' || options.type === 'datetime') {
7117 				this.type = options.type;
7118 			}
7119 		}
7120 		
7121 		if (options.calendar) {
7122 			this.calName = options.calendar;
7123 		}
7124 		
7125 		if (options.length) {
7126 			if (options.length === 'short' ||
7127 				options.length === 'medium' ||
7128 				options.length === 'long' ||
7129 				options.length === 'full') {
7130 				// only use the first char to save space in the json files
7131 				this.length = options.length.charAt(0);
7132 			}
7133 		}
7134 		
7135 		if (options.date) {
7136 			arr = options.date.split("");
7137 			arr.sort(function (left, right) {
7138 				return (left < right) ? -1 : ((right < left) ? 1 : 0);
7139 			});
7140 			bad = false;
7141 			for (i = 0; i < arr.length; i++) {
7142 				if (arr[i] !== 'd' && arr[i] !== 'm' && arr[i] !== 'y' && arr[i] !== 'w' && arr[i] !== 'n') {
7143 					bad = true;
7144 					break;
7145 				}
7146 			}
7147 			if (!bad) {
7148 				this.dateComponents = arr.join("");
7149 			}
7150 		}
7151 
7152 		if (options.time) {
7153 			arr = options.time.split("");
7154 			arr.sort(function (left, right) {
7155 				return (left < right) ? -1 : ((right < left) ? 1 : 0);
7156 			});
7157 			this.badTime = false;
7158 			for (i = 0; i < arr.length; i++) {
7159 				if (arr[i] !== 'h' && arr[i] !== 'm' && arr[i] !== 's' && arr[i] !== 'a' && arr[i] !== 'z') {
7160 					this.badTime = true;
7161 					break;
7162 				}
7163 			}
7164 			if (!this.badTime) {
7165 				this.timeComponents = arr.join("");
7166 			}
7167 		}
7168 		
7169 		if (options.clock && (options.clock === '12' || options.clock === '24')) {
7170 			this.clock = options.clock;
7171 		}
7172 		
7173 		if (options.template) {
7174 			// many options are not useful when specifying the template directly, so zero
7175 			// them out.
7176 			this.type = "";
7177 			this.length = "";
7178 			this.dateComponents = "";
7179 			this.timeComponents = "";
7180 			
7181 			this.template = options.template;
7182 		}
7183 		
7184 		if (options.timezone) {
7185 			if (options.timezone instanceof ilib.TimeZone) {
7186 				this.tz = options.timezone;
7187 			} else {
7188 				this.tz = new ilib.TimeZone({
7189 					locale: this.locale, 
7190 					id: options.timezone
7191 				});
7192 			}
7193 		} else if (options.locale) {
7194 			// if an explicit locale was given, then get the time zone for that locale
7195 			this.tz = new ilib.TimeZone({
7196 				locale: this.locale
7197 			});
7198 		} // else just assume time zone "local"
7199 		
7200 		if (typeof(options.useNative) === 'boolean') {
7201 			this.useNative = options.useNative;
7202 		}
7203 		
7204 		if (typeof(options.meridiems) !== 'undefined' && 
7205 				(options.meridiems === "chinese" || 
7206 				 options.meridiems === "gregorian" || 
7207 				 options.meridiems === "ethiopic")) {
7208 			this.meridiems = options.meridiems;
7209 		}
7210 		
7211 		if (typeof(options.sync) !== 'undefined') {
7212 			sync = (options.sync === true);
7213 		}
7214 		
7215 		loadParams = options.loadParams;
7216 	}
7217 
7218 	if (!ilib.DateFmt.cache) {
7219 		ilib.DateFmt.cache = {};
7220 	}
7221 
7222 	new ilib.LocaleInfo(this.locale, {
7223 		sync: sync,
7224 		loadParams: loadParams, 
7225 		onLoad: ilib.bind(this, function (li) {
7226 			this.locinfo = li;
7227 			
7228 			// get the default calendar name from the locale, and if the locale doesn't define
7229 			// one, use the hard-coded gregorian as the last resort
7230 			this.calName = this.calName || this.locinfo.getCalendar() || "gregorian";
7231 			this.cal = ilib.Cal.newInstance({
7232 				type: this.calName
7233 			});
7234 			if (!this.cal) {
7235 				this.cal = new ilib.Cal.Gregorian();
7236 			}
7237 			
7238 			if (this.meridiems === "default") {
7239 				this.meridiems = li.getMeridiemsStyle();
7240 			}
7241 
7242 			/*
7243 			if (this.timeComponents &&
7244 					(this.clock === '24' || 
7245 					(!this.clock && this.locinfo.getClock() === "24"))) {
7246 				// make sure we don't have am/pm in 24 hour mode unless the user specifically
7247 				// requested it in the time component option
7248 				this.timeComponents = this.timeComponents.replace("a", "");
7249 			}
7250 			*/
7251 
7252 			// load the strings used to translate the components
7253 			new ilib.ResBundle({
7254 				locale: this.locale,
7255 				name: "sysres",
7256 				sync: sync,
7257 				loadParams: loadParams, 
7258 				onLoad: ilib.bind(this, function (rb) {
7259 					this.sysres = rb;
7260 					
7261 					if (!this.template) {
7262 						ilib.loadData({
7263 							object: ilib.DateFmt, 
7264 							locale: this.locale, 
7265 							name: "dateformats.json", 
7266 							sync: sync, 
7267 							loadParams: loadParams, 
7268 							callback: ilib.bind(this, function (formats) {
7269 								if (!formats) {
7270 									formats = ilib.data.dateformats || ilib.DateFmt.defaultFmt;
7271 									var spec = this.locale.getSpec().replace(/-/g, '_');
7272 									ilib.DateFmt.cache[spec] = formats;
7273 								}
7274 								if (typeof(this.clock) === 'undefined') {
7275 									// default to the locale instead
7276 									this.clock = this.locinfo.getClock();
7277 								}
7278 								this._initTemplate(formats);
7279 								this._massageTemplate();
7280 								if (options && typeof(options.onLoad) === 'function') {
7281 									options.onLoad(this);
7282 								}
7283 							})
7284 						});
7285 					} else {
7286 						this._massageTemplate();
7287 						if (options && typeof(options.onLoad) === 'function') {
7288 							options.onLoad(this);
7289 						}
7290 					}
7291 				})
7292 			});	
7293 		})
7294 	});
7295 };
7296 
7297 // used in getLength
7298 ilib.DateFmt.lenmap = {
7299 	"s": "short",
7300 	"m": "medium",
7301 	"l": "long",
7302 	"f": "full"
7303 };
7304 
7305 ilib.DateFmt.zeros = "0000";
7306 
7307 ilib.DateFmt.defaultFmt = {
7308 	"gregorian": {
7309 		"order": "{date} {time}",
7310 		"date": {
7311 			"dmwy": "EEE d/MM/yyyy",
7312 			"dmy": "d/MM/yyyy",
7313 			"dmw": "EEE d/MM",
7314 			"dm": "d/MM",
7315 			"my": "MM/yyyy",
7316 			"dw": "EEE d",
7317 			"d": "dd",
7318 			"m": "MM",
7319 			"y": "yyyy",
7320 			"n": "NN",
7321 			"w": "EEE"
7322 		},
7323 		"time": {
7324 			"12": "h:mm:ssa",
7325 			"24": "H:mm:ss"
7326 		},
7327 		"range": {
7328 			"c00": "{st} - {et}, {sd}/{sm}/{sy}",
7329 			"c01": "{sd}/{sm} {st} - {ed}/{em} {et}, {sy}",
7330 			"c02": "{sd}/{sm} {st} - {ed}/{em} {et}, {sy}",
7331 			"c03": "{sd}/{sm}/{sy} {st} - {ed}/{em}/{ey} {et}",
7332 			"c10": "{sd}-{ed}/{sm}/{sy}",
7333 			"c11": "{sd}/{sm} - {ed}/{em} {sy}",
7334 			"c12": "{sd}/{sm}/{sy} - {ed}/{em}/{ey}",
7335 			"c20": "{sm}/{sy} - {em}/{ey}",
7336 			"c30": "{sy} - {ey}"
7337 		}
7338 	},
7339 	"islamic": "gregorian",
7340 	"hebrew": "gregorian",
7341 	"julian": "gregorian",
7342 	"buddhist": "gregorian",
7343 	"persian": "gregorian",
7344 	"persian-algo": "gregorian",
7345 	"han": "gregorian"
7346 };
7347 
7348 /**
7349 * @static
7350 * @private
7351 */
7352 ilib.DateFmt.monthNameLenMap = {
7353 	"short" : "N",
7354 	"medium": "NN",
7355 	"long":   "MMM",
7356 	"full":   "MMMM"
7357 };
7358 
7359 /**
7360 * @static
7361 * @private
7362 */
7363 ilib.DateFmt.weekDayLenMap = {
7364 	"short" : "E",
7365 	"medium": "EE",
7366 	"long":   "EEE",
7367 	"full":   "EEEE"
7368 };
7369 
7370 /**
7371 	 * @protected
7372 	 * @param {Object.<string, (string|{s:string,m:string,l:string,f:string})>} obj Object to search
7373 	 * @param {string} components Format components to search
7374 	 * @param {string} length Length of the requested format
7375 	 * @return {string|undefined} the requested format
7376 	 */
7377 
7378 /**
7379 * @static
7380 * @public
7381 * The options may contain any of the following properties:
7382 *
7383 * <ul>
7384 * <li><i>locale</i> - locale to use when formatting the date/time. If the locale is
7385 * not specified, then the default locale of the app or web page will be used.
7386 * 
7387 * <li><i>meridiems</i> - string that specifies what style of meridiems to use with this 
7388 * format. The choices are "default", "gregorian", "ethiopic", and "chinese". The "default" 
7389 * style is often the simple Gregorian AM/PM, but the actual style is chosen by the locale. 
7390 * (For almost all locales, the Gregorian AM/PM style is most frequently used.)
7391 * The "ethiopic" style uses 5 different meridiems for "morning", "noon", "afternoon", 
7392 * "evening", and "night". The "chinese" style uses 7 different meridiems corresponding 
7393 * to the various parts of the day. N.B. Even for the Chinese locales, the default is "gregorian"
7394 * when formatting dates in the Gregorian calendar.
7395 * </ul>
7396 *
7397 * @param {Object} options options governing the way this date formatter instance works for getting meridiems range
7398 * @return {Array.<{name:string,start:string,end:string}>}
7399 */
7400 ilib.DateFmt.getMeridiemsRange = function (options) {
7401 	options = options || {};
7402 	var args = {};
7403 	if (options.locale) {
7404 		args.locale = options.locale;
7405 	}
7406 
7407 	if (options.meridiems) {
7408 		args.meridiems = options.meridiems;
7409 	}
7410 
7411 	var fmt = new ilib.DateFmt(args);
7412 
7413 	return fmt.getMeridiemsRange();
7414 };
7415 
7416 ilib.DateFmt.prototype = {
7417 	/**
7418 	 * @protected
7419 	 */
7420 	_initTemplate: function (formats) {
7421 		if (formats[this.calName]) {
7422 			/** 
7423 			 * @private
7424 			 * @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})>}}
7425 			 */
7426 			this.formats = formats[this.calName];
7427 			if (typeof(this.formats) === "string") {
7428 				// alias to another calendar type
7429 				this.formats = formats[this.formats];
7430 			}
7431 			
7432 			this.template = "";
7433 			
7434 			switch (this.type) {
7435 				case "datetime":
7436 					this.template = (this.formats && this._getLengthFormat(this.formats.order, this.length)) || "{date} {time}";
7437 					this.template = this.template.replace("{date}", this._getFormat(this.formats.date, this.dateComponents, this.length) || "");
7438 					this.template = this.template.replace("{time}", this._getFormat(this.formats.time[this.clock], this.timeComponents, this.length) || "");
7439 					break;
7440 				case "date":
7441 					this.template = this._getFormat(this.formats.date, this.dateComponents, this.length);
7442 					break;
7443 				case "time":
7444 					this.template = this._getFormat(this.formats.time[this.clock], this.timeComponents, this.length);
7445 					break;
7446 			}
7447 		} else {
7448 			throw "No formats available for calendar " + this.calName + " in locale " + this.locale.toString();
7449 		}
7450 	},
7451 	
7452 	/**
7453 	 * @protected
7454 	 */
7455 	_massageTemplate: function () {
7456 		var i;
7457 		
7458 		if (this.clock && this.template) {
7459 			// explicitly set the hours to the requested type
7460 			var temp = "";
7461 			switch (this.clock) {
7462 				case "24":
7463 					for (i = 0; i < this.template.length; i++) {
7464 						if (this.template.charAt(i) == "'") {
7465 							temp += this.template.charAt(i++);
7466 							while (i < this.template.length && this.template.charAt(i) !== "'") {
7467 								temp += this.template.charAt(i++);
7468 							}
7469 							if (i < this.template.length) {
7470 								temp += this.template.charAt(i);
7471 							}
7472 						} else if (this.template.charAt(i) == 'K') {
7473 							temp += 'k';
7474 						} else if (this.template.charAt(i) == 'h') {
7475 							temp += 'H';
7476 						} else {
7477 							temp += this.template.charAt(i);
7478 						}
7479 					}
7480 					this.template = temp;
7481 					break;
7482 				case "12":
7483 					for (i = 0; i < this.template.length; i++) {
7484 						if (this.template.charAt(i) == "'") {
7485 							temp += this.template.charAt(i++);
7486 							while (i < this.template.length && this.template.charAt(i) !== "'") {
7487 								temp += this.template.charAt(i++);
7488 							}
7489 							if (i < this.template.length) {
7490 								temp += this.template.charAt(i);
7491 							}
7492 						} else if (this.template.charAt(i) == 'k') {
7493 							temp += 'K';
7494 						} else if (this.template.charAt(i) == 'H') {
7495 							temp += 'h';
7496 						} else {
7497 							temp += this.template.charAt(i);
7498 						}
7499 					}
7500 					this.template = temp;
7501 					break;
7502 			}
7503 		}
7504 		
7505 		// tokenize it now for easy formatting
7506 		this.templateArr = this._tokenize(this.template);
7507 
7508 		var digits;
7509 		// set up the mapping to native or alternate digits if necessary
7510 		if (typeof(this.useNative) === "boolean") {
7511 			if (this.useNative) {
7512 				digits = this.locinfo.getNativeDigits();
7513 				if (digits) {
7514 					this.digits = digits;
7515 				}
7516 			}
7517 		} else if (this.locinfo.getDigitsStyle() === "native") {
7518 			digits = this.locinfo.getNativeDigits();
7519 			if (digits) {
7520 				this.useNative = true;
7521 				this.digits = digits;
7522 			}
7523 		}
7524 	},
7525     
7526 	/**
7527 	 * Convert the template into an array of date components separated by formatting chars.
7528 	 * @protected
7529 	 * @param {string} template Format template to tokenize into components
7530 	 * @return {Array.<string>} a tokenized array of date format components
7531 	 */
7532 	_tokenize: function (template) {
7533 		var i = 0, start, ch, letter, arr = [];
7534 		
7535 		// console.log("_tokenize: tokenizing template " + template);
7536 		if (template) {
7537 			while (i < template.length) {
7538 				ch = template.charAt(i);
7539 				start = i;
7540 				if (ch === "'") {
7541 					// console.log("found quoted string");
7542 					i++;
7543 					// escaped string - push as-is, then dequote later
7544 					while (i < template.length && template.charAt(i) !== "'") {
7545 						i++;
7546 					}
7547 					if (i < template.length) {
7548 						i++;	// grab the other quote too
7549 					}
7550 				} else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
7551 					letter = template.charAt(i);
7552 					// console.log("found letters " + letter);
7553 					while (i < template.length && ch === letter) {
7554 						ch = template.charAt(++i);
7555 					}
7556 				} else {
7557 					// console.log("found other");
7558 					while (i < template.length && ch !== "'" && (ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z')) {
7559 						ch = template.charAt(++i);
7560 					}
7561 				}
7562 				arr.push(template.substring(start,i));
7563 				// console.log("start is " + start + " i is " + i + " and substr is " + template.substring(start,i));
7564 			}
7565 		}
7566 		return arr;
7567 	},
7568                           
7569 	/**
7570 	 * @protected
7571 	 * @param {Object.<string, (string|{s:string,m:string,l:string,f:string})>} obj Object to search
7572 	 * @param {string} components Format components to search
7573 	 * @param {string} length Length of the requested format
7574 	 * @return {string|undefined} the requested format
7575 	 */
7576 	_getFormat: function getFormat(obj, components, length) {
7577 		if (typeof(components) !== 'undefined' && obj && obj[components]) {
7578 			return this._getLengthFormat(obj[components], length);
7579 		}
7580 		return undefined;
7581 	},
7582 
7583 	/**
7584 	 * @protected
7585 	 * @param {(string|{s:string,m:string,l:string,f:string})} obj Object to search
7586 	 * @param {string} length Length of the requested format
7587 	 * @return {(string|undefined)} the requested format
7588 	 */
7589 	_getLengthFormat: function getLengthFormat(obj, length) {
7590 		if (typeof(obj) === 'string') {
7591 			return obj;
7592 		} else if (obj[length]) {
7593 			return obj[length];
7594 		}
7595 		return undefined;
7596 	},
7597 
7598 	/**
7599 	 * Return the locale used with this formatter instance.
7600 	 * @return {ilib.Locale} the ilib.Locale instance for this formatter
7601 	 */
7602 	getLocale: function() {
7603 		return this.locale;
7604 	},
7605 	
7606 	/**
7607 	 * Return the template string that is used to format date/times for this
7608 	 * formatter instance. This will work, even when the template property is not explicitly 
7609 	 * given in the options to the constructor. Without the template option, the constructor 
7610 	 * will build the appropriate template according to the options and use that template
7611 	 * in the format method. 
7612 	 * 
7613 	 * @return {string} the format template for this formatter
7614 	 */
7615 	getTemplate: function() {
7616 		return this.template;
7617 	},
7618 	
7619 	/**
7620 	 * Return the type of this formatter. The type is a string that has one of the following
7621 	 * values: "time", "date", "datetime".
7622 	 * @return {string} the type of the formatter
7623 	 */
7624 	getType: function() {
7625 		return this.type;
7626 	},
7627 	
7628 	/**
7629 	 * Return the name of the calendar used to format date/times for this
7630 	 * formatter instance.
7631 	 * @return {string} the name of the calendar used by this formatter
7632 	 */
7633 	getCalendar: function () {
7634 		return this.cal.getType();
7635 	},
7636 	
7637 	/**
7638 	 * Return the length used to format date/times in this formatter. This is either the
7639 	 * value of the length option to the constructor, or the default value.
7640 	 * 
7641 	 * @return {string} the length of formats this formatter returns
7642 	 */
7643 	getLength: function () {
7644 		return ilib.DateFmt.lenmap[this.length] || "";
7645 	},
7646 	
7647 	/**
7648 	 * Return the date components that this formatter formats. This is either the 
7649 	 * value of the date option to the constructor, or the default value. If this
7650 	 * formatter is a time-only formatter, this method will return the empty 
7651 	 * string. The date component letters may be specified in any order in the 
7652 	 * constructor, but this method will reorder the given components to a standard 
7653 	 * order.
7654 	 * 
7655 	 * @return {string} the date components that this formatter formats
7656 	 */
7657 	getDateComponents: function () {
7658 		return this.dateComponents || "";
7659 	},
7660 
7661 	/**
7662 	 * Return the time components that this formatter formats. This is either the 
7663 	 * value of the time option to the constructor, or the default value. If this
7664 	 * formatter is a date-only formatter, this method will return the empty 
7665 	 * string. The time component letters may be specified in any order in the 
7666 	 * constructor, but this method will reorder the given components to a standard 
7667 	 * order.
7668 	 * 
7669 	 * @return {string} the time components that this formatter formats
7670 	 */
7671 	getTimeComponents: function () {
7672 		return this.timeComponents || "";
7673 	},
7674 
7675 	/**
7676 	 * Return the time zone used to format date/times for this formatter
7677 	 * instance.
7678 	 * @return a string naming the time zone
7679 	 */
7680 	getTimeZone: function () {
7681 		// Lazy load the time zone. If it wasn't explicitly set up before, set 
7682 		// it up now, but use the 
7683 		// default TZ for the locale. This way, if the caller never uses the
7684 		// time zone in their format, we never have to load up a TimeZone
7685 		// instance into this formatter.
7686 		if (!this.tz) {
7687 			this.tz = new ilib.TimeZone({id: ilib.getTimeZone()});
7688 		}
7689 		return this.tz;
7690 	},
7691 	/**
7692 	 * Return the clock option set in the constructor. If the clock option was
7693 	 * not given, the default from the locale is returned instead.
7694 	 * @return {string} "12" or "24" depending on whether this formatter uses
7695 	 * the 12-hour or 24-hour clock
7696 	 */
7697 	getClock: function () {
7698 		return this.clock || this.locinfo.getClock();
7699 	},
7700 	/**
7701 	 * Return the meridiems range in current locale. 
7702 	 * @return {Array.<{name:string,start:string,end:string}>}
7703 	 */
7704 	getMeridiemsRange: function () {
7705 		var result;
7706 		var _getSysString = function (key) {
7707 			return (this.sysres.getString(undefined, key + "-" + this.calName) || this.sysres.getString(undefined, key)).toString();
7708 		};
7709 
7710 		switch (this.meridiems) {
7711 		case "chinese":
7712 			result = [
7713 				{
7714 					name: _getSysString.call(this, "azh0"),
7715 					start: "00:00",
7716 					end: "05:59"
7717 				},
7718 				{
7719 					name: _getSysString.call(this, "azh1"),
7720 					start: "06:00",
7721 					end: "08:59"
7722 				},
7723 				{
7724 					name: _getSysString.call(this, "azh2"),
7725 					start: "09:00",
7726 					end: "11:59"
7727 				},
7728 				{
7729 					name: _getSysString.call(this, "azh3"),
7730 					start: "12:00",
7731 					end: "12:59"
7732 				},
7733 				{
7734 					name: _getSysString.call(this, "azh4"),
7735 					start: "13:00",
7736 					end: "17:59"
7737 				},
7738 				{
7739 					name: _getSysString.call(this, "azh5"),
7740 					start: "18:00",
7741 					end: "20:59"
7742 				},
7743 				{
7744 					name: _getSysString.call(this, "azh6"),
7745 					start: "21:00",
7746 					end: "23:59"
7747 				}
7748 			];
7749 			break;
7750 		case "ethiopic":
7751 			result = [
7752 				{
7753 					name: _getSysString.call(this, "a0-ethiopic"),
7754 					start: "00:00",
7755 					end: "05:59"
7756 				},
7757 				{
7758 					name: _getSysString.call(this, "a1-ethiopic"),
7759 					start: "06:00",
7760 					end: "06:00"
7761 				},
7762 				{
7763 					name: _getSysString.call(this, "a2-ethiopic"),
7764 					start: "06:01",
7765 					end: "11:59"
7766 				},
7767 				{
7768 					name: _getSysString.call(this, "a3-ethiopic"),
7769 					start: "12:00",
7770 					end: "17:59"
7771 				},
7772 				{
7773 					name: _getSysString.call(this, "a4-ethiopic"),
7774 					start: "18:00",
7775 					end: "23:59"
7776 				}
7777 			];
7778 			break;
7779 		default:
7780 			result = [
7781 				{
7782 					name: _getSysString.call(this, "a0"),
7783 					start: "00:00",
7784 					end: "11:59"
7785 				},
7786 				{
7787 					name: _getSysString.call(this, "a1"),
7788 					start: "12:00",
7789 					end: "23:59"
7790 				}
7791 			];
7792 			break;
7793 		}
7794 
7795 		return result;
7796 	},
7797 	
7798 	/**
7799 	 * @private
7800 	 */
7801 	_getTemplate: function (prefix, calendar) {
7802 		if (calendar !== "gregorian") {
7803 			return prefix + "-" + calendar;
7804 		}
7805 		return prefix;
7806 	},
7807 
7808 	/**
7809 	 * Returns an array of the months of the year, formatted to the optional length specified.
7810 	 * i.e. ...getMonthsOfYear() OR ...getMonthsOfYear({length: "short"})
7811 	 * <p>
7812 	 * The options parameter may contain any of the following properties:
7813 	 * 
7814 	 * <ul>
7815 	 * <li><i>length</i> - length of the names of the months being sought. This may be one of
7816 	 * "short", "medium", "long", or "full"
7817 	 * <li><i>date</i> - retrieve the names of the months in the date of the given date
7818 	 * <li><i>year</i> - retrieve the names of the months in the given year. In some calendars,
7819 	 * the months have different names depending if that year is a leap year or not.
7820 	 * </ul>
7821 	 * 
7822 	 * @param  {Object=} options an object-literal that contains any of the above properties
7823 	 * @return {Array} an array of the names of all of the months of the year in the current calendar
7824 	 */
7825 	getMonthsOfYear: function(options) {
7826 		var length = (options && options.length) || this.getLength(),
7827 			template = ilib.DateFmt.monthNameLenMap[length],
7828 			months = [undefined],
7829 			date,
7830 			monthCount;
7831 		
7832 		if (options) {
7833 			if (options.date) {
7834 				date = ilib.Date._dateToIlib(options.date); 	
7835 			}
7836 			
7837 			if (options.year) {
7838 				date = ilib.Date.newInstance({year: options.year, month: 1, day: 1, type: this.cal.getType()});
7839 			}
7840 		}
7841 		
7842 		if (!date) {
7843 			date = this.cal.newDateInstance();
7844 		}
7845 
7846 		monthCount = this.cal.getNumMonths(date.getYears());
7847 		for (var i = 1; i <= monthCount; i++) {
7848 			months[i] = this.sysres.getString(this._getTemplate(template + i, this.cal.getType())).toString();
7849 		}
7850 		return months;
7851 	},
7852 
7853 	/**
7854 	 * Returns an array of the days of the week, formatted to the optional length specified.
7855 	 * i.e. ...getDaysOfWeek() OR ...getDaysOfWeek({length: "short"})
7856 	 * <p>
7857 	 * The options parameter may contain any of the following properties:
7858 	 * 
7859 	 * <ul>
7860 	 * <li><i>length</i> - length of the names of the months being sought. This may be one of
7861 	 * "short", "medium", "long", or "full"
7862 	 * </ul>
7863 	 * @param  {Object=} options an object-literal that contains one key 
7864 	 *                   "length" with the standard length strings
7865 	 * @return {Array} an array of all of the names of the days of the week
7866 	 */
7867 	getDaysOfWeek: function(options) {
7868 		var length = (options && options.length) || this.getLength(),
7869 			template = ilib.DateFmt.weekDayLenMap[length],
7870 			days = [];
7871 		for (var i = 0; i < 7; i++) {
7872 			days[i] = this.sysres.getString(this._getTemplate(template + i, this.cal.getType())).toString();
7873 		}
7874 		return days;
7875 	},
7876 
7877 	
7878 	/**
7879 	 * Convert this formatter to a string representation by returning the
7880 	 * format template. This method delegates to getTemplate.
7881 	 * 
7882 	 * @return {string} the format template
7883 	 */
7884 	toString: function() {
7885 		return this.getTemplate();
7886 	},
7887 	
7888 	/*
7889 	 * @private
7890 	 * Left pad the str to the given length of digits with zeros
7891 	 * @param {string} str the string to pad
7892 	 * @param {number} length the desired total length of the output string, padded 
7893 	 */
7894 	_pad: function (str, length) {
7895 		if (typeof(str) !== 'string') {
7896 			str = "" + str;
7897 		}
7898 		var start = 0;
7899 		if (str.charAt(0) === '-') {
7900 			start++;
7901 		}
7902 		return (str.length >= length+start) ? str : str.substring(0, start) + ilib.DateFmt.zeros.substring(0,length-str.length+start) + str.substring(start);
7903 	},
7904 	
7905 	/*
7906 	 * @private
7907 	 * Format a date according to a sequence of components. 
7908 	 * @param {ilib.Date} date a date/time object to format
7909 	 * @param {Array.<string>} templateArr an array of components to format
7910 	 * @return {string} the formatted date
7911 	 */
7912 	_formatTemplate: function (date, templateArr) {
7913 		var i, key, temp, tz, str = "";
7914 		for (i = 0; i < templateArr.length; i++) {
7915 			switch (templateArr[i]) {
7916 				case 'd':
7917 					str += (date.day || 1);
7918 					break;
7919 				case 'dd':
7920 					str += this._pad(date.day || "1", 2);
7921 					break;
7922 				case 'yy':
7923 					temp = "" + ((date.year || 0) % 100);
7924 					str += this._pad(temp, 2);
7925 					break;
7926 				case 'yyyy':
7927 					str += this._pad(date.year || "0", 4);
7928 					break;
7929 				case 'M':
7930 					str += (date.month || 1);
7931 					break;
7932 				case 'MM':
7933 					str += this._pad(date.month || "1", 2);
7934 					break;
7935 				case 'h':
7936 					temp = (date.hour || 0) % 12;
7937 					if (temp == 0) {
7938 						temp = "12";
7939 					}
7940 					str += temp; 
7941 					break;
7942 				case 'hh':
7943 					temp = (date.hour || 0) % 12;
7944 					if (temp == 0) {
7945 						temp = "12";
7946 					}
7947 					str += this._pad(temp, 2);
7948 					break;
7949 				/*
7950 				case 'j':
7951 					temp = (date.hour || 0) % 12 + 1;
7952 					str += temp; 
7953 					break;
7954 				case 'jj':
7955 					temp = (date.hour || 0) % 12 + 1;
7956 					str += this._pad(temp, 2);
7957 					break;
7958 				*/
7959 				case 'K':
7960 					temp = (date.hour || 0) % 12;
7961 					str += temp; 
7962 					break;
7963 				case 'KK':
7964 					temp = (date.hour || 0) % 12;
7965 					str += this._pad(temp, 2);
7966 					break;
7967 
7968 				case 'H':
7969 					str += (date.hour || "0");
7970 					break;
7971 				case 'HH':
7972 					str += this._pad(date.hour || "0", 2);
7973 					break;
7974 				case 'k':
7975 					str += (date.hour == 0 ? "24" : date.hour);
7976 					break;
7977 				case 'kk':
7978 					temp = (date.hour == 0 ? "24" : date.hour);
7979 					str += this._pad(temp, 2);
7980 					break;
7981 
7982 				case 'm':
7983 					str += (date.minute || "0");
7984 					break;
7985 				case 'mm':
7986 					str += this._pad(date.minute || "0", 2);
7987 					break;
7988 				case 's':
7989 					str += (date.minute || "0");
7990 					break;
7991 				case 'ss':
7992 					str += this._pad(date.second || "0", 2);
7993 					break;
7994 				case 'S':
7995 					str += (date.millisecond || "0");
7996 					break;
7997 				case 'SSS':
7998 					str += this._pad(date.millisecond || "0", 3);
7999 					break;
8000 
8001 				case 'N':
8002 				case 'NN':
8003 				case 'MMM':
8004 				case 'MMMM':
8005 					key = templateArr[i] + (date.month || 1);
8006 					str += (this.sysres.getString(undefined, key + "-" + this.calName) || this.sysres.getString(undefined, key));
8007 					break;
8008 
8009 				case 'E':
8010 				case 'EE':
8011 				case 'EEE':
8012 				case 'EEEE':
8013 					key = templateArr[i] + date.getDayOfWeek();
8014 					//console.log("finding " + key + " in the resources");
8015 					str += (this.sysres.getString(undefined, key + "-" + this.calName) || this.sysres.getString(undefined, key));
8016 					break;
8017 					
8018 				case 'a':
8019 					switch (this.meridiems) {
8020 					case "chinese":
8021 						if (date.hour < 6) {
8022 							key = "azh0";	// before dawn
8023 						} else if (date.hour < 9) {
8024 							key = "azh1";	// morning
8025 						} else if (date.hour < 12) {
8026 							key = "azh2";	// late morning/day before noon
8027 						} else if (date.hour < 13) {
8028 							key = "azh3";	// noon hour/midday
8029 						} else if (date.hour < 18) {
8030 							key = "azh4";	// afternoon
8031 						} else if (date.hour < 21) {
8032 							key = "azh5";	// evening time/dusk
8033 						} else {
8034 							key = "azh6";	// night time
8035 						}
8036 						break;
8037 					case "ethiopic":
8038 						if (date.hour < 6) {
8039 							key = "a0-ethiopic";	// morning
8040 						} else if (date.hour === 6 && date.minute === 0) {
8041 							key = "a1-ethiopic";	// noon
8042 						} else if (date.hour >= 6 && date.hour < 12) {
8043 							key = "a2-ethiopic";	// afternoon
8044 						} else if (date.hour >= 12 && date.hour < 18) {
8045 							key = "a3-ethiopic";	// evening
8046 						} else if (date.hour >= 18) {
8047 							key = "a4-ethiopic";	// night
8048 						}
8049 						break;
8050 					default:
8051 						key = date.hour < 12 ? "a0" : "a1";
8052 						break;
8053 					}
8054 					//console.log("finding " + key + " in the resources");
8055 					str += (this.sysres.getString(undefined, key + "-" + this.calName) || this.sysres.getString(undefined, key));
8056 					break;
8057 					
8058 				case 'w':
8059 					str += date.getWeekOfYear();
8060 					break;
8061 				case 'ww':
8062 					str += this._pad(date.getWeekOfYear(), 2);
8063 					break;
8064 
8065 				case 'D':
8066 					str += date.getDayOfYear();
8067 					break;
8068 				case 'DD':
8069 					str += this._pad(date.getDayOfYear(), 2);
8070 					break;
8071 				case 'DDD':
8072 					str += this._pad(date.getDayOfYear(), 3);
8073 					break;
8074 				case 'W':
8075 					str += date.getWeekOfMonth(this.locale);
8076 					break;
8077 
8078 				case 'G':
8079 					key = "G" + date.getEra();
8080 					str += (this.sysres.getString(undefined, key + "-" + this.calName) || this.sysres.getString(undefined, key));
8081 					break;
8082 
8083 				case 'O':
8084 					temp = this.sysres.getString("1#1st|2#2nd|3#3rd|21#21st|22#22nd|23#23rd|31#31st|#{num}th", "ordinalChoice");
8085 					str += temp.formatChoice(date.day, {num: date.day});
8086 					break;
8087 					
8088 				case 'z': // general time zone
8089 					tz = this.getTimeZone(); // lazy-load the tz
8090 					str += tz.getDisplayName(date, "standard");
8091 					break;
8092 				case 'Z': // RFC 822 time zone
8093 					tz = this.getTimeZone(); // lazy-load the tz
8094 					str += tz.getDisplayName(date, "rfc822");
8095 					break;
8096 
8097 				default:
8098 					str += templateArr[i].replace(/'/g, "");
8099 					break;
8100 			}
8101 		}
8102 
8103 		if (this.digits) {
8104 			str = ilib.mapString(str, this.digits);
8105 		}
8106 		return str;
8107 	},
8108 	
8109 	/**
8110 	 * Format a particular date instance according to the settings of this
8111 	 * formatter object. The type of the date instance being formatted must 
8112 	 * correspond exactly to the calendar type with which this formatter was 
8113 	 * constructed. If the types are not compatible, this formatter will
8114 	 * produce bogus results.
8115 	 * 
8116 	 * @param {Date|Number|String|ilib.Date|ilib.JulianDay|null|undefined} dateLike a date-like object to format
8117 	 * @return {string} the formatted version of the given date instance
8118 	 */
8119 	format: function (dateLike) {
8120 		var thisZoneName = this.tz && this.tz.getId() || "local";
8121 
8122 		var date = ilib.Date._dateToIlib(dateLike, thisZoneName);
8123 		
8124 		if (!date.getCalendar || !(date instanceof ilib.Date)) {
8125 			throw "Wrong date type passed to ilib.DateFmt.format()";
8126 		}
8127 		
8128 		var dateZoneName = date.timezone || "local";
8129 		
8130 		// convert to the time zone of this formatter before formatting
8131 		if (dateZoneName !== thisZoneName || date.getCalendar() !== this.calName) {
8132 			// console.log("Differing time zones date: " + dateZoneName + " and fmt: " + thisZoneName + ". Converting...");
8133 			// this will recalculate the date components based on the new time zone
8134 			// and/or convert a date in another calendar to the current calendar before formatting it
8135 			var newDate = ilib.Date.newInstance({
8136 				type: this.calName,
8137 				timezone: thisZoneName,
8138 				julianday: date.getJulianDay()
8139 			});
8140 			
8141 			date = newDate;
8142 		}
8143 		return this._formatTemplate(date, this.templateArr);
8144 	},
8145 	
8146 	/**
8147 	 * Return a string that describes a date relative to the given 
8148 	 * reference date. The string returned is text that for the locale that
8149 	 * was specified when the formatter instance was constructed.<p>
8150 	 * 
8151 	 * The date can be in the future relative to the reference date or in
8152 	 * the past, and the formatter will generate the appropriate string.<p>
8153 	 * 
8154 	 * The text used to describe the relative reference depends on the length
8155 	 * of time between the date and the reference. If the time was in the
8156 	 * past, it will use the "ago" phrase, and in the future, it will use
8157 	 * the "in" phrase. Examples:<p>
8158 	 * 
8159 	 * <ul>
8160 	 * <li>within a minute: either "X seconds ago" or "in X seconds"
8161 	 * <li>within an hour: either "X minutes ago" or "in X minutes"
8162 	 * <li>within a day: either "X hours ago" or "in X hours"
8163 	 * <li>within 2 weeks: either "X days ago" or "in X days"
8164 	 * <li>within 12 weeks (~3 months): either "X weeks ago" or "in X weeks"
8165 	 * <li>within two years: either "X months ago" or "in X months"
8166 	 * <li>longer than 2 years: "X years ago" or "in X years"
8167 	 * </ul>
8168 	 * 
8169 	 * @param {Date|Number|String|ilib.Date|ilib.JulianDay|null|undefined} reference a date that the date parameter should be relative to
8170 	 * @param {Date|Number|String|ilib.Date|ilib.JulianDay|null|undefined} date a date being formatted
8171 	 * @throws "Wrong calendar type" when the start or end dates are not the same
8172 	 * calendar type as the formatter itself
8173 	 * @return {string} the formatted relative date
8174 	 */
8175 	formatRelative: function(reference, date) {
8176 		reference = ilib.Date._dateToIlib(reference);
8177 		date = ilib.Date._dateToIlib(date);
8178 		
8179 		var referenceRd, dateRd, fmt, time, diff, num;
8180 		
8181 		if (typeof(reference) !== 'object' || !reference.getCalendar || reference.getCalendar() !== this.calName ||
8182 			typeof(date) !== 'object' || !date.getCalendar || date.getCalendar() !== this.calName) {
8183 			throw "Wrong calendar type";
8184 		}
8185 		
8186 		referenceRd = reference.getRataDie();
8187 		dateRd = date.getRataDie();
8188 		
8189 		if (dateRd < referenceRd) {
8190 			diff = referenceRd - dateRd;
8191 			fmt = this.sysres.getString("{duration} ago");
8192 		} else {
8193 			diff = dateRd - referenceRd;
8194 			fmt = this.sysres.getString("in {duration}");
8195 		}
8196 		
8197 		if (diff < 0.000694444) {
8198 			num = Math.round(diff * 86400);
8199 			switch (this.length) {
8200 				case 's':
8201 					time = this.sysres.getString("#{num}s");
8202 					break;
8203 				case 'm':
8204 					time = this.sysres.getString("1#1 se|#{num} sec");
8205 					break;
8206 				case 'l':
8207 					time = this.sysres.getString("1#1 sec|#{num} sec");
8208 					break;
8209 				default:
8210 				case 'f':
8211 					time = this.sysres.getString("1#1 second|#{num} seconds");
8212 					break;
8213 			}
8214 		} else if (diff < 0.041666667) {
8215 			num = Math.round(diff * 1440);
8216 			switch (this.length) {
8217 				case 's':
8218 					time = this.sysres.getString("#{num}m", "durationShortMinutes");
8219 					break;
8220 				case 'm':
8221 					time = this.sysres.getString("1#1 mi|#{num} min");
8222 					break;
8223 				case 'l':
8224 					time = this.sysres.getString("1#1 min|#{num} min");
8225 					break;
8226 				default:
8227 				case 'f':
8228 					time = this.sysres.getString("1#1 minute|#{num} minutes");
8229 					break;
8230 			}
8231 		} else if (diff < 1) {
8232 			num = Math.round(diff * 24);
8233 			switch (this.length) {
8234 				case 's':
8235 					time = this.sysres.getString("#{num}h");
8236 					break;
8237 				case 'm':
8238 					time = this.sysres.getString("1#1 hr|#{num} hrs", "durationMediumHours");
8239 					break;
8240 				case 'l':
8241 					time = this.sysres.getString("1#1 hr|#{num} hrs");
8242 					break;
8243 				default:
8244 				case 'f':
8245 					time = this.sysres.getString("1#1 hour|#{num} hours");
8246 					break;
8247 			}
8248 		} else if (diff < 14) {
8249 			num = Math.round(diff);
8250 			switch (this.length) {
8251 				case 's':
8252 					time = this.sysres.getString("#{num}d");
8253 					break;
8254 				case 'm':
8255 					time = this.sysres.getString("1#1 dy|#{num} dys");
8256 					break;
8257 				case 'l':
8258 					time = this.sysres.getString("1#1 day|#{num} days", "durationLongDays");
8259 					break;
8260 				default:
8261 				case 'f':
8262 					time = this.sysres.getString("1#1 day|#{num} days");
8263 					break;
8264 			}
8265 		} else if (diff < 84) {
8266 			num = Math.round(diff/7);
8267 			switch (this.length) {
8268 				case 's':
8269 					time = this.sysres.getString("#{num}w");
8270 					break;
8271 				case 'm':
8272 					time = this.sysres.getString("1#1 wk|#{num} wks", "durationMediumWeeks");
8273 					break;
8274 				case 'l':
8275 					time = this.sysres.getString("1#1 wk|#{num} wks");
8276 					break;
8277 				default:
8278 				case 'f':
8279 					time = this.sysres.getString("1#1 week|#{num} weeks");
8280 					break;
8281 			}
8282 		} else if (diff < 730) {
8283 			num = Math.round(diff/30.4);
8284 			switch (this.length) {
8285 				case 's':
8286 					time = this.sysres.getString("#{num}m", "durationShortMonths");
8287 					break;
8288 				case 'm':
8289 					time = this.sysres.getString("1#1 mo|#{num} mos");
8290 					break;
8291 				case 'l':
8292 					time = this.sysres.getString("1#1 mon|#{num} mons");
8293 					break;
8294 				default:
8295 				case 'f':
8296 					time = this.sysres.getString("1#1 month|#{num} months");
8297 					break;
8298 			}
8299 		} else {
8300 			num = Math.round(diff/365);
8301 			switch (this.length) {
8302 				case 's':
8303 					time = this.sysres.getString("#{num}y");
8304 					break;
8305 				case 'm':
8306 					time = this.sysres.getString("1#1 yr|#{num} yrs", "durationMediumYears");
8307 					break;
8308 				case 'l':
8309 					time = this.sysres.getString("1#1 yr|#{num} yrs");
8310 					break;
8311 				default:
8312 				case 'f':
8313 					time = this.sysres.getString("1#1 year|#{num} years");
8314 					break;
8315 			}
8316 		}
8317 		return fmt.format({duration: time.formatChoice(num, {num: num})});
8318 	}
8319 };
8320 
8321 /*
8322  * datefmt.js - Date formatter definition
8323  * 
8324  * Copyright © 2012-2014, JEDLSoft
8325  *
8326  * Licensed under the Apache License, Version 2.0 (the "License");
8327  * you may not use this file except in compliance with the License.
8328  * You may obtain a copy of the License at
8329  *
8330  *     http://www.apache.org/licenses/LICENSE-2.0
8331  *
8332  * Unless required by applicable law or agreed to in writing, software
8333  * distributed under the License is distributed on an "AS IS" BASIS,
8334  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8335  *
8336  * See the License for the specific language governing permissions and
8337  * limitations under the License.
8338  */
8339 
8340 /*
8341 !depends 
8342 ilibglobal.js 
8343 locale.js 
8344 date.js 
8345 strings.js 
8346 calendar.js
8347 localeinfo.js
8348 timezone.js
8349 datefmt.js
8350 calendar/gregorian.js
8351 util/jsutils.js
8352 */
8353 
8354 // !data dateformats sysres
8355 
8356 /**
8357  * @class
8358  * Create a new date range formatter instance. The date range formatter is immutable once
8359  * it is created, but can format as many different date ranges as needed with the same
8360  * options. Create different date range formatter instances for different purposes
8361  * and then keep them cached for use later if you have more than one range to
8362  * format.<p>
8363  * 
8364  * The options may contain any of the following properties:
8365  * 
8366  * <ul>
8367  * <li><i>locale</i> - locale to use when formatting the date/times in the range. If the 
8368  * locale is not specified, then the default locale of the app or web page will be used.
8369  * 
8370  * <li><i>calendar</i> - the type of calendar to use for this format. The value should
8371  * be a sting containing the name of the calendar. Currently, the supported
8372  * types are "gregorian", "julian", "arabic", "hebrew", or "chinese". If the
8373  * calendar is not specified, then the default calendar for the locale is used. When the
8374  * calendar type is specified, then the format method must be called with an instance of
8375  * the appropriate date type. (eg. Gregorian calendar means that the format method must 
8376  * be called with a GregDate instance.)
8377  *  
8378  * <li><i>timezone</i> - time zone to use when formatting times. This may be a time zone
8379  * instance or a time zone specifier string in RFC 822 format. If not specified, the
8380  * default time zone for the locale is used.
8381  * 
8382  * <li><i>length</i> - Specify the length of the format to use as a string. The length 
8383  * is the approximate size of the formatted string.
8384  * 
8385  * <ul>
8386  * <li><i>short</i> - use a short representation of the time. This is the most compact format possible for the locale.
8387  * <li><i>medium</i> - use a medium length representation of the time. This is a slightly longer format.
8388  * <li><i>long</i> - use a long representation of the time. This is a fully specified format, but some of the textual 
8389  * components may still be abbreviated. (eg. "Tue" instead of "Tuesday")
8390  * <li><i>full</i> - use a full representation of the time. This is a fully specified format where all the textual 
8391  * components are spelled out completely.
8392  * </ul>
8393  * 
8394  * eg. The "short" format for an en_US range may be "MM/yy - MM/yy", whereas the long format might be 
8395  * "MMM, yyyy - MMM, yyyy". In the long format, the month name is textual instead of numeric 
8396  * and is longer, the year is 4 digits instead of 2, and the format contains slightly more 
8397  * spaces and formatting characters.<p>
8398  * 
8399  * Note that the length parameter does not specify which components are to be formatted. The
8400  * components that are formatted depend on the length of time in the range.
8401  * 
8402  * <li><i>clock</i> - specify that formatted times should use a 12 or 24 hour clock if the
8403  * format happens to include times. Valid values are "12" and "24".<p>
8404  * 
8405  * In some locales, both clocks are used. For example, in en_US, the general populace uses
8406  * a 12 hour clock with am/pm, but in the US military or in nautical or aeronautical or 
8407  * scientific writing, it is more common to use a 24 hour clock. This property allows you to
8408  * construct a formatter that overrides the default for the locale.<p>
8409  * 
8410  * If this property is not specified, the default is to use the most widely used convention
8411  * for the locale.
8412  * <li>onLoad - a callback function to call when the date range format object is fully 
8413  * loaded. When the onLoad option is given, the DateRngFmt object will attempt to
8414  * load any missing locale data using the ilib loader callback.
8415  * When the constructor is done (even if the data is already preassembled), the 
8416  * onLoad function is called with the current instance as a parameter, so this
8417  * callback can be used with preassembled or dynamic loading or a mix of the two. 
8418  * 
8419  * <li>sync - tell whether to load any missing locale data synchronously or 
8420  * asynchronously. If this option is given as "false", then the "onLoad"
8421  * callback must be given, as the instance returned from this constructor will
8422  * not be usable for a while.
8423  *  
8424  * <li><i>loadParams</i> - an object containing parameters to pass to the 
8425  * loader callback function when locale data is missing. The parameters are not
8426  * interpretted or modified in any way. They are simply passed along. The object 
8427  * may contain any property/value pairs as long as the calling code is in
8428  * agreement with the loader callback function as to what those parameters mean.
8429  * </ul>
8430  * <p>
8431  * 
8432  * Depends directive: !depends daterangefmt.js
8433  * 
8434  * @constructor
8435  * @param {Object} options options governing the way this date range formatter instance works
8436  */
8437 ilib.DateRngFmt = function(options) {
8438 	var sync = true;
8439 	var loadParams = undefined;
8440 	this.locale = new ilib.Locale();
8441 	this.length = "s";
8442 	
8443 	if (options) {
8444 		if (options.locale) {
8445 			this.locale = (typeof(options.locale) === 'string') ? new ilib.Locale(options.locale) : options.locale;
8446 		}
8447 		
8448 		if (options.calendar) {
8449 			this.calName = options.calendar;
8450 		}
8451 		
8452 		if (options.length) {
8453 			if (options.length === 'short' ||
8454 				options.length === 'medium' ||
8455 				options.length === 'long' ||
8456 				options.length === 'full') {
8457 				// only use the first char to save space in the json files
8458 				this.length = options.length.charAt(0);
8459 			}
8460 		}
8461 		if (typeof(options.sync) !== 'undefined') {
8462 			sync = (options.sync == true);
8463 		}
8464 		
8465 		loadParams = options.loadParams;
8466 	}
8467 	
8468 	var opts = {};
8469 	ilib.shallowCopy(options, opts);
8470 	opts.sync = sync;
8471 	opts.loadParams = loadParams;
8472 	
8473 	/**
8474 	 * @private
8475 	 */
8476 	opts.onLoad = ilib.bind(this, function (fmt) {
8477 		this.dateFmt = fmt;
8478 		if (fmt) {
8479 			this.locinfo = this.dateFmt.locinfo;
8480 
8481 			// get the default calendar name from the locale, and if the locale doesn't define
8482 			// one, use the hard-coded gregorian as the last resort
8483 			this.calName = this.calName || this.locinfo.getCalendar() || "gregorian";
8484 			this.cal = ilib.Cal.newInstance({
8485 				type: this.calName
8486 			});
8487 			if (!this.cal) {
8488 				this.cal = new ilib.Cal.Gregorian();
8489 			}
8490 			
8491 			this.timeTemplate = this.dateFmt._getFormat(this.dateFmt.formats.time[this.dateFmt.clock], this.dateFmt.timeComponents, this.length) || "hh:mm";
8492 			this.timeTemplateArr = this.dateFmt._tokenize(this.timeTemplate);
8493 			
8494 			if (options && typeof(options.onLoad) === 'function') {
8495 				options.onLoad(this);
8496 			}
8497 		}
8498 	});
8499 
8500 	// delegate a bunch of the formatting to this formatter
8501 	new ilib.DateFmt(opts);
8502 };
8503 
8504 ilib.DateRngFmt.prototype = {
8505 	/**
8506 	 * Return the locale used with this formatter instance.
8507 	 * @return {ilib.Locale} the ilib.Locale instance for this formatter
8508 	 */
8509 	getLocale: function() {
8510 		return this.locale;
8511 	},
8512 	
8513 	/**
8514 	 * Return the name of the calendar used to format date/times for this
8515 	 * formatter instance.
8516 	 * @return {string} the name of the calendar used by this formatter
8517 	 */
8518 	getCalendar: function () {
8519 		return this.dateFmt.getCalendar();
8520 	},
8521 	
8522 	/**
8523 	 * Return the length used to format date/times in this formatter. This is either the
8524 	 * value of the length option to the constructor, or the default value.
8525 	 * 
8526 	 * @return {string} the length of formats this formatter returns
8527 	 */
8528 	getLength: function () {
8529 		return ilib.DateFmt.lenmap[this.length] || "";
8530 	},
8531 	
8532 	/**
8533 	 * Return the time zone used to format date/times for this formatter
8534 	 * instance.
8535 	 * @return {ilib.TimeZone} a string naming the time zone
8536 	 */
8537 	getTimeZone: function () {
8538 		return this.dateFmt.getTimeZone();
8539 	},
8540 	
8541 	/**
8542 	 * Return the clock option set in the constructor. If the clock option was
8543 	 * not given, the default from the locale is returned instead.
8544 	 * @return {string} "12" or "24" depending on whether this formatter uses
8545 	 * the 12-hour or 24-hour clock
8546 	 */
8547 	getClock: function () {
8548 		return this.dateFmt.getClock();
8549 	},
8550 	
8551 	/**
8552 	 * Format a date/time range according to the settings of the current
8553 	 * formatter. The range is specified as being from the "start" date until
8554 	 * the "end" date. <p>
8555 	 * 
8556 	 * The template that the date/time range uses depends on the
8557 	 * length of time between the dates, on the premise that a long date range
8558 	 * which is too specific is not useful. For example, when giving
8559 	 * the dates of the 100 Years War, in most situations it would be more 
8560 	 * appropriate to format the range as "1337 - 1453" than to format it as 
8561 	 * "10:37am November 9, 1337 - 4:37pm July 17, 1453", as the latter format 
8562 	 * is much too specific given the length of time that the range represents.
8563 	 * If a very specific, but long, date range really is needed, the caller 
8564 	 * should format two specific dates separately and put them 
8565 	 * together as you might with other normal strings.<p>
8566 	 * 
8567 	 * The format used for a date range contains the following date components,
8568 	 * where the order of those components is rearranged and the component values 
8569 	 * are translated according to each locale:
8570 	 * 
8571 	 * <ul>
8572 	 * <li>within 3 days: the times of day, dates, months, and years
8573 	 * <li>within 730 days (2 years): the dates, months, and years
8574 	 * <li>within 3650 days (10 years): the months and years
8575 	 * <li>longer than 10 years: the years only 
8576 	 * </ul>
8577 	 * 
8578 	 * In general, if any of the date components share a value between the
8579 	 * start and end date, that component is only given once. For example,
8580 	 * if the range is from November 15, 2011 to November 26, 2011, the 
8581 	 * start and end dates both share the same month and year. The 
8582 	 * range would then be formatted as "November 15-26, 2011". <p>
8583 	 * 
8584 	 * If you want to format a length of time instead of a particular range of
8585 	 * time (for example, the length of an event rather than the specific start time
8586 	 * and end time of that event), then use a duration formatter instance 
8587 	 * (ilib.DurFmt) instead. The formatRange method will make sure that each component 
8588 	 * of the date/time is within the normal range for that component. For example, 
8589 	 * the minutes will always be between 0 and 59, no matter what is specified in 
8590 	 * the date to format, because that is the normal range for minutes. A duration 
8591 	 * format will allow the number of minutes to exceed 59. For example, if you 
8592 	 * were displaying the length of a movie that is 198 minutes long, the minutes
8593 	 * component of a duration could be 198.<p>
8594 	 * 
8595 	 * @param {ilib.Date} start the starting date/time of the range. This must be of 
8596 	 * the same calendar type as the formatter itself. 
8597 	 * @param {ilib.Date} end the ending date/time of the range. This must be of the 
8598 	 * same calendar type as the formatter itself.
8599 	 * @throws "Wrong calendar type" when the start or end dates are not the same
8600 	 * calendar type as the formatter itself
8601 	 * @return {string} a date range formatted for the locale
8602 	 */
8603 	format: function (start, end) {
8604 		var startRd, endRd, fmt = "", yearTemplate, monthTemplate, dayTemplate;
8605 		
8606 		if (typeof(start) !== 'object' || !start.getCalendar || start.getCalendar() !== this.calName ||
8607 			typeof(end) !== 'object' || !end.getCalendar || end.getCalendar() !== this.calName) {
8608 			throw "Wrong calendar type";
8609 		}
8610 		
8611 		startRd = start.getRataDie();
8612 		endRd = end.getRataDie();
8613 		
8614 		// 
8615 		// legend:
8616 		// c00 - difference is less than 3 days. Year, month, and date are same, but time is different
8617 		// c01 - difference is less than 3 days. Year and month are same but date and time are different
8618 		// c02 - difference is less than 3 days. Year is same but month, date, and time are different. (ie. it straddles a month boundary)
8619 		// c03 - difference is less than 3 days. Year, month, date, and time are all different. (ie. it straddles a year boundary)
8620 		// c10 - difference is less than 2 years. Year and month are the same, but date is different.
8621 		// c11 - difference is less than 2 years. Year is the same, but month, date, and time are different.
8622 		// c12 - difference is less than 2 years. All fields are different. (ie. straddles a year boundary)
8623 		// c20 - difference is less than 10 years. All fields are different.
8624 		// c30 - difference is more than 10 years. All fields are different.
8625 		//
8626 		
8627 		if (endRd - startRd < 3) {
8628 			if (start.year === end.year) {
8629 				if (start.month === end.month) {
8630 					if (start.day === end.day) {
8631 						fmt = new ilib.String(this.dateFmt._getFormat(this.dateFmt.formats.range, "c00", this.length));
8632 					} else {
8633 						fmt = new ilib.String(this.dateFmt._getFormat(this.dateFmt.formats.range, "c01", this.length));
8634 					}
8635 				} else {
8636 					fmt = new ilib.String(this.dateFmt._getFormat(this.dateFmt.formats.range, "c02", this.length));
8637 				}
8638 			} else {
8639 				fmt = new ilib.String(this.dateFmt._getFormat(this.dateFmt.formats.range, "c03", this.length));
8640 			}
8641 		} else if (endRd - startRd < 730) {
8642 			if (start.year === end.year) {
8643 				if (start.month === end.month) {
8644 					fmt = new ilib.String(this.dateFmt._getFormat(this.dateFmt.formats.range, "c10", this.length));
8645 				} else {
8646 					fmt = new ilib.String(this.dateFmt._getFormat(this.dateFmt.formats.range, "c11", this.length));
8647 				}
8648 			} else {
8649 				fmt = new ilib.String(this.dateFmt._getFormat(this.dateFmt.formats.range, "c12", this.length));
8650 			}
8651 		} else if (endRd - startRd < 3650) {
8652 			fmt = new ilib.String(this.dateFmt._getFormat(this.dateFmt.formats.range, "c20", this.length));
8653 		} else {
8654 			fmt = new ilib.String(this.dateFmt._getFormat(this.dateFmt.formats.range, "c30", this.length));
8655 		}
8656 
8657 		yearTemplate = this.dateFmt._tokenize(this.dateFmt._getFormat(this.dateFmt.formats.date, "y", this.length) || "yyyy");
8658 		monthTemplate = this.dateFmt._tokenize(this.dateFmt._getFormat(this.dateFmt.formats.date, "m", this.length) || "MM");
8659 		dayTemplate = this.dateFmt._tokenize(this.dateFmt._getFormat(this.dateFmt.formats.date, "d", this.length) || "dd");
8660 		
8661 		/*
8662 		console.log("fmt is " + fmt.toString());
8663 		console.log("year template is " + yearTemplate);
8664 		console.log("month template is " + monthTemplate);
8665 		console.log("day template is " + dayTemplate);
8666 		*/
8667 		
8668 		return fmt.format({
8669 			sy: this.dateFmt._formatTemplate(start, yearTemplate),
8670 			sm: this.dateFmt._formatTemplate(start, monthTemplate),
8671 			sd: this.dateFmt._formatTemplate(start, dayTemplate),
8672 			st: this.dateFmt._formatTemplate(start, this.timeTemplateArr),
8673 			ey: this.dateFmt._formatTemplate(end, yearTemplate),
8674 			em: this.dateFmt._formatTemplate(end, monthTemplate),
8675 			ed: this.dateFmt._formatTemplate(end, dayTemplate),
8676 			et: this.dateFmt._formatTemplate(end, this.timeTemplateArr)
8677 		});
8678 	}
8679 };
8680 
8681 /*
8682  * hebrew.js - Represent a Hebrew calendar object.
8683  * 
8684  * Copyright © 2012-2014, JEDLSoft
8685  *
8686  * Licensed under the Apache License, Version 2.0 (the "License");
8687  * you may not use this file except in compliance with the License.
8688  * You may obtain a copy of the License at
8689  *
8690  *     http://www.apache.org/licenses/LICENSE-2.0
8691  *
8692  * Unless required by applicable law or agreed to in writing, software
8693  * distributed under the License is distributed on an "AS IS" BASIS,
8694  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8695  *
8696  * See the License for the specific language governing permissions and
8697  * limitations under the License.
8698  */
8699 
8700 
8701 /* !depends calendar.js locale.js date.js julianday.js util/utils.js util/math.js */
8702 
8703 /**
8704  * @class
8705  * Construct a new Hebrew calendar object. This class encodes information about
8706  * the Hebrew (Jewish) calendar. The Hebrew calendar is a tabular hebrew 
8707  * calendar where the dates are calculated by arithmetic rules. This differs from 
8708  * the religious Hebrew calendar which is used to mark the beginning of particular 
8709  * holidays. The religious calendar depends on the first sighting of the new 
8710  * crescent moon to determine the first day of the new month. Because humans and 
8711  * weather are both involved, the actual time of sighting varies, so it is not 
8712  * really possible to precalculate the religious calendar. Certain groups, such 
8713  * as the Hebrew Society of North America, decreed in in 2007 that they will use
8714  * a calendar based on calculations rather than observations to determine the 
8715  * beginning of lunar months, and therefore the dates of holidays.<p>
8716  * 
8717  * Depends directive: !depends hebrew.js
8718  * 
8719  * @constructor
8720  * @implements ilib.Cal
8721  */
8722 ilib.Cal.Hebrew = function() {
8723 	this.type = "hebrew";
8724 };
8725 
8726 
8727 /**
8728  * Return the number of days elapsed in the Hebrew calendar before the
8729  * given year starts.
8730  * @private
8731  * @param {number} year the year for which the number of days is sought
8732  * @return {number} the number of days elapsed in the Hebrew calendar before the
8733  * given year starts
8734  */
8735 ilib.Cal.Hebrew.elapsedDays = function(year) {
8736 	var months = Math.floor(((235*year) - 234)/19);
8737 	var parts = 204 + 793 * ilib.mod(months, 1080);
8738 	var hours = 11 + 12 * months + 793 * Math.floor(months/1080) + 
8739 		Math.floor(parts/1080);
8740 	var days = 29 * months + Math.floor(hours/24);
8741 	return (ilib.mod(3 * (days + 1), 7) < 3) ? days + 1 : days;
8742 };
8743 
8744 /**
8745  * Return the number of days that the New Year's (Rosh HaShanah) in the Hebrew 
8746  * calendar will be corrected for the given year. Corrections are caused because New 
8747  * Year's is not allowed to start on certain days of the week. To deal with 
8748  * it, the start of the new year is corrected for the next year by adding a 
8749  * day to the 8th month (Heshvan) and/or the 9th month (Kislev) in the current
8750  * year to make them 30 days long instead of 29.
8751  * 
8752  * @private
8753  * @param {number} year the year for which the correction is sought
8754  * @param {number} elapsed number of days elapsed up to this year
8755  * @return {number} the number of days correction in the current year to make sure
8756  * Rosh HaShanah does not fall on undesirable days of the week
8757  */
8758 ilib.Cal.Hebrew.newYearsCorrection = function(year, elapsed) {
8759 	var lastYear = ilib.Cal.Hebrew.elapsedDays(year-1),
8760 		thisYear = elapsed,
8761 		nextYear = ilib.Cal.Hebrew.elapsedDays(year+1);
8762 	
8763 	return (nextYear - thisYear) == 356 ? 2 : ((thisYear - lastYear) == 382 ? 1 : 0);
8764 };
8765 
8766 /**
8767  * Return the rata die date of the new year for the given hebrew year.
8768  * @private
8769  * @param {number} year the year for which the new year is needed
8770  * @return {number} the rata die date of the new year
8771  */
8772 ilib.Cal.Hebrew.newYear = function(year) {
8773 	var elapsed = ilib.Cal.Hebrew.elapsedDays(year); 
8774 	
8775 	return elapsed + ilib.Cal.Hebrew.newYearsCorrection(year, elapsed);
8776 };
8777 
8778 /**
8779  * Return the number of days in the given year. Years contain a variable number of
8780  * days because the date of Rosh HaShanah (New Year's) changes so that it doesn't
8781  * fall on particular days of the week. Days are added to the months of Heshvan
8782  * and/or Kislev in the previous year in order to prevent the current year's New
8783  * Year from being on Sunday, Wednesday, or Friday.
8784  * 
8785  * @param {number} year the year for which the length is sought
8786  * @return {number} number of days in the given year
8787  */
8788 ilib.Cal.Hebrew.daysInYear = function(year) {
8789 	return ilib.Cal.Hebrew.newYear(year+1) - ilib.Cal.Hebrew.newYear(year);
8790 };
8791 
8792 /**
8793  * Return true if the given year contains a long month of Heshvan. That is,
8794  * it is 30 days instead of 29.
8795  * 
8796  * @private
8797  * @param {number} year the year in which that month is questioned
8798  * @return {boolean} true if the given year contains a long month of Heshvan
8799  */
8800 ilib.Cal.Hebrew.longHeshvan = function(year) {
8801 	return ilib.mod(ilib.Cal.Hebrew.daysInYear(year), 10) === 5;
8802 };
8803 
8804 /**
8805  * Return true if the given year contains a long month of Kislev. That is,
8806  * it is 30 days instead of 29.
8807  * 
8808  * @private
8809  * @param {number} year the year in which that month is questioned
8810  * @return {boolean} true if the given year contains a short month of Kislev
8811  */
8812 ilib.Cal.Hebrew.longKislev = function(year) {
8813 	return ilib.mod(ilib.Cal.Hebrew.daysInYear(year), 10) !== 3;
8814 };
8815 
8816 /**
8817  * Return the date of the last day of the month for the given year. The date of
8818  * the last day of the month is variable because a number of months gain an extra 
8819  * day in leap years, and it is variable which months gain a day for each leap 
8820  * year and which do not.
8821  * 
8822  * @param {number} month the month for which the number of days is sought
8823  * @param {number} year the year in which that month is
8824  * @return {number} the number of days in the given month and year
8825  */
8826 ilib.Cal.Hebrew.prototype.lastDayOfMonth = function(month, year) {
8827 	switch (month) {
8828 		case 2: 
8829 		case 4: 
8830 		case 6: 
8831 		case 10: 
8832 			return 29;
8833 		case 13:
8834 			return this.isLeapYear(year) ? 29 : 0;
8835 		case 8:
8836 			return ilib.Cal.Hebrew.longHeshvan(year) ? 30 : 29;
8837 		case 9:
8838 			return ilib.Cal.Hebrew.longKislev(year) ? 30 : 29;
8839 		case 12:
8840 		case 1:
8841 		case 3:
8842 		case 5:
8843 		case 7:
8844 		case 11:
8845 			return 30;
8846 		default:
8847 			return 0;
8848 	}
8849 };
8850 
8851 /**
8852  * Return the number of months in the given year. The number of months in a year varies
8853  * for luni-solar calendars because in some years, an extra month is needed to extend the 
8854  * days in a year to an entire solar year. The month is represented as a 1-based number
8855  * where 1=first month, 2=second month, etc.
8856  * 
8857  * @param {number} year a year for which the number of months is sought
8858  */
8859 ilib.Cal.Hebrew.prototype.getNumMonths = function(year) {
8860 	return this.isLeapYear(year) ? 13 : 12;
8861 };
8862 
8863 /**
8864  * Return the number of days in a particular month in a particular year. This function
8865  * can return a different number for a month depending on the year because of leap years.
8866  *
8867  * @param {number} month the month for which the length is sought
8868  * @param {number} year the year within which that month can be found
8869  * @returns {number} the number of days within the given month in the given year, or
8870  * 0 for an invalid month in the year
8871  */
8872 ilib.Cal.Hebrew.prototype.getMonLength = function(month, year) {
8873 	if (month < 1 || month > 13 || (month == 13 && !this.isLeapYear(year))) {
8874 		return 0;
8875 	}
8876 	return this.lastDayOfMonth(month, year);
8877 };
8878 
8879 /**
8880  * Return true if the given year is a leap year in the Hebrew calendar.
8881  * The year parameter may be given as a number, or as a HebrewDate object.
8882  * @param {number|Object} year the year for which the leap year information is being sought
8883  * @returns {boolean} true if the given year is a leap year
8884  */
8885 ilib.Cal.Hebrew.prototype.isLeapYear = function(year) {
8886 	var y = (typeof(year) == 'number') ? year : year.year;
8887 	return (ilib.mod(1 + 7 * y, 19) < 7);
8888 };
8889 
8890 /**
8891  * Return the type of this calendar.
8892  * 
8893  * @returns {string} the name of the type of this calendar 
8894  */
8895 ilib.Cal.Hebrew.prototype.getType = function() {
8896 	return this.type;
8897 };
8898 
8899 /**
8900  * Return a date instance for this calendar type using the given
8901  * options.
8902  * @param {Object} options options controlling the construction of 
8903  * the date instance
8904  * @returns {ilib.Date} a date appropriate for this calendar type
8905  */
8906 ilib.Cal.Hebrew.prototype.newDateInstance = function (options) {
8907 	return new ilib.Date.HebrewDate(options);
8908 };
8909 
8910 /*register this calendar for the factory method */
8911 ilib.Cal._constructors["hebrew"] = ilib.Cal.Hebrew;
8912 
8913 /*
8914  * hebrewdate.js - Represent a date in the Hebrew calendar
8915  * 
8916  * Copyright © 2012-2014, JEDLSoft
8917  *
8918  * Licensed under the Apache License, Version 2.0 (the "License");
8919  * you may not use this file except in compliance with the License.
8920  * You may obtain a copy of the License at
8921  *
8922  *     http://www.apache.org/licenses/LICENSE-2.0
8923  *
8924  * Unless required by applicable law or agreed to in writing, software
8925  * distributed under the License is distributed on an "AS IS" BASIS,
8926  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8927  *
8928  * See the License for the specific language governing permissions and
8929  * limitations under the License.
8930  */
8931 
8932 /* !depends 
8933 date.js 
8934 calendar/hebrew.js
8935 calendar/ratadie.js
8936 util/utils.js
8937 util/math.js
8938 julianday.js 
8939 */
8940 
8941 /**
8942  * @class
8943  * Construct a new Hebrew RD date number object. The constructor parameters can 
8944  * contain any of the following properties:
8945  * 
8946  * <ul>
8947  * <li><i>unixtime<i> - sets the time of this instance according to the given 
8948  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
8949  * 
8950  * <li><i>julianday</i> - sets the time of this instance according to the given
8951  * Julian Day instance or the Julian Day given as a float
8952  * 
8953  * <li><i>year</i> - any integer, including 0
8954  * 
8955  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
8956  * 
8957  * <li><i>day</i> - 1 to 31
8958  * 
8959  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
8960  * is always done with an unambiguous 24 hour representation
8961  * 
8962  * <li><i>parts</i> - 0 to 1079. Specify the halaqim parts of an hour. Either specify 
8963  * the parts or specify the minutes, seconds, and milliseconds, but not both. 
8964  * 
8965  * <li><i>minute</i> - 0 to 59
8966  * 
8967  * <li><i>second</i> - 0 to 59
8968  * 
8969  * <li><i>millisecond</i> - 0 to 999
8970  * 
8971  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
8972  * </ul>
8973  *
8974  * If the constructor is called with another Hebrew date instance instead of
8975  * a parameter block, the other instance acts as a parameter block and its
8976  * settings are copied into the current instance.<p>
8977  * 
8978  * If the constructor is called with no arguments at all or if none of the 
8979  * properties listed above are present, then the RD is calculate based on 
8980  * the current date at the time of instantiation. <p>
8981  * 
8982  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
8983  * specified in the params, it is assumed that they have the smallest possible
8984  * value in the range for the property (zero or one).<p>
8985  * 
8986  * Depends directive: !depends hebrewdate.js
8987  * 
8988  * @private
8989  * @constructor
8990  * @extends ilib.Date.RataDie
8991  * @param {Object=} params parameters that govern the settings and behaviour of this Hebrew RD date
8992  */
8993 ilib.Date.HebrewRataDie = function(params) {
8994 	this.cal = params && params.cal || new ilib.Cal.Hebrew();
8995 	this.rd = undefined;
8996 	ilib.Date.RataDie.call(this, params);
8997 };
8998 
8999 ilib.Date.HebrewRataDie.prototype = new ilib.Date.RataDie();
9000 ilib.Date.HebrewRataDie.prototype.parent = ilib.Date.RataDie;
9001 ilib.Date.HebrewRataDie.prototype.constructor = ilib.Date.HebrewRataDie;
9002 
9003 /**
9004  * The difference between a zero Julian day and the first day of the Hebrew 
9005  * calendar: sunset on Monday, Tishri 1, 1 = September 7, 3760 BC Gregorian = JD 347997.25
9006  * @private
9007  * @const
9008  * @type number
9009  */
9010 ilib.Date.HebrewRataDie.prototype.epoch = 347997.25;
9011 
9012 /**
9013  * Calculate the Rata Die (fixed day) number of the given date from the
9014  * date components.
9015  * 
9016  * @private
9017  * @param {Object} date the date components to calculate the RD from
9018  */
9019 ilib.Date.HebrewRataDie.prototype._setDateComponents = function(date) {
9020 	var elapsed = ilib.Cal.Hebrew.elapsedDays(date.year);
9021 	var days = elapsed +
9022 		ilib.Cal.Hebrew.newYearsCorrection(date.year, elapsed) +
9023 		date.day - 1;
9024 	var sum = 0, table;
9025 	
9026 	//console.log("getRataDie: converting " +  JSON.stringify(date));
9027 	//console.log("getRataDie: days is " +  days);
9028 	//console.log("getRataDie: new years correction is " +  ilib.Cal.Hebrew.newYearsCorrection(date.year, elapsed));
9029 	
9030 	table = this.cal.isLeapYear(date.year) ? 
9031 				ilib.Date.HebrewDate.cumMonthLengthsLeap :
9032 				ilib.Date.HebrewDate.cumMonthLengths;
9033 	sum = table[date.month-1];
9034 	
9035 	// gets cumulative without correction, so now add in the correction
9036 	if ((date.month < 7 || date.month > 8) && ilib.Cal.Hebrew.longHeshvan(date.year)) {
9037 		sum++;
9038 	}
9039 	if ((date.month < 7 || date.month > 9) && ilib.Cal.Hebrew.longKislev(date.year)) {
9040 		sum++;
9041 	}
9042 	// console.log("getRataDie: cum days is now " +  sum);
9043 	
9044 	days += sum;
9045 	
9046 	// the date starts at sunset, which we take as 18:00, so the hours from
9047 	// midnight to 18:00 are on the current Gregorian day, and the hours from
9048 	// 18:00 to midnight are on the previous Gregorian day. So to calculate the 
9049 	// number of hours into the current day that this time represents, we have
9050 	// to count from 18:00 to midnight first, and add in 6 hours if the time is
9051 	// less than 18:00
9052 	var minute, second, millisecond;
9053 	
9054 	if (typeof(date.parts) !== 'undefined') {
9055 		// The parts (halaqim) of the hour. This can be a number from 0 to 1079.
9056 		var parts = parseInt(date.parts, 10);
9057 		var seconds = parseInt(parts, 10) * 3.333333333333;
9058 		minute = Math.floor(seconds / 60);
9059 		seconds -= minute * 60;
9060 		second = Math.floor(seconds);
9061 		millisecond = (seconds - second);	
9062 	} else {
9063 		minute = parseInt(date.minute, 10) || 0;
9064 		second = parseInt(date.second, 10) || 0;
9065 		millisecond = parseInt(date.millisecond, 10) || 0;
9066 	}
9067 		
9068 	var time;
9069 	if (date.hour >= 18) {
9070 		time = ((date.hour - 18 || 0) * 3600000 +
9071 			(minute || 0) * 60000 +
9072 			(second || 0) * 1000 +
9073 			(millisecond || 0)) / 
9074 			86400000;
9075 	} else {
9076 		time = 0.25 +	// 6 hours from 18:00 to midnight on the previous gregorian day
9077 				((date.hour || 0) * 3600000 +
9078 				(minute || 0) * 60000 +
9079 				(second || 0) * 1000 +
9080 				(millisecond || 0)) / 
9081 				86400000;
9082 	}
9083 	
9084 	//console.log("getRataDie: rd is " +  (days + time));
9085 	this.rd = days + time;
9086 };
9087 	
9088 /**
9089  * Return the rd number of the particular day of the week on or before the 
9090  * given rd. eg. The Sunday on or before the given rd.
9091  * @private
9092  * @param {number} rd the rata die date of the reference date
9093  * @param {number} dayOfWeek the day of the week that is being sought relative 
9094  * to the current date
9095  * @return {number} the rd of the day of the week
9096  */
9097 ilib.Date.HebrewRataDie.prototype._onOrBefore = function(rd, dayOfWeek) {
9098 	return rd - ilib.mod(Math.floor(rd) - dayOfWeek + 1, 7);
9099 };
9100 
9101 /**
9102  * @class
9103  * Construct a new civil Hebrew date object. The constructor can be called
9104  * with a params object that can contain the following properties:<p>
9105  * 
9106  * <ul>
9107  * <li><i>julianday</i> - the Julian Day to set into this date
9108  * <li><i>year</i> - any integer except 0. Years go from -1 (BCE) to 1 (CE), skipping the zero year
9109  * <li><i>month</i> - 1 to 12, where 1 means Nisan, 2 means Iyyar, etc.
9110  * <li><i>day</i> - 1 to 30
9111  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
9112  * is always done with an unambiguous 24 hour representation
9113  * <li><i>parts</i> - 0 to 1079. Specify the halaqim parts of an hour. Either specify 
9114  * the parts or specify the minutes, seconds, and milliseconds, but not both. 
9115  * <li><i>minute</i> - 0 to 59
9116  * <li><i>second</i> - 0 to 59
9117  * <li><i>millisecond</i> - 0 to 999
9118  * <li><i>locale</i> - the ilib.TimeZone instance or time zone name as a string 
9119  * of this julian date. The date/time is kept in the local time. The time zone
9120  * is used later if this date is formatted according to a different time zone and
9121  * the difference has to be calculated, or when the date format has a time zone
9122  * component in it.
9123  * <li><i>timezone</i> - the time zone of this instance. If the time zone is not 
9124  * given, it can be inferred from this locale. For locales that span multiple
9125  * time zones, the one with the largest population is chosen as the one that 
9126  * represents the locale. 
9127  * 
9128  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
9129  * </ul>
9130  * 
9131  * If called with another Hebrew date argument, the date components of the given
9132  * date are copied into the current one.<p>
9133  * 
9134  * If the constructor is called with no arguments at all or if none of the 
9135  * properties listed above 
9136  * from <i>julianday</i> through <i>millisecond</i> are present, then the date 
9137  * components are 
9138  * filled in with the current date at the time of instantiation. Note that if
9139  * you do not give the time zone when defaulting to the current time and the 
9140  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
9141  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
9142  * Mean Time").<p>
9143  * 
9144  * Depends directive: !depends hebrewdate.js
9145  * 
9146  * @constructor
9147  * @extends ilib.Date
9148  * @param {Object=} params parameters that govern the settings and behaviour of this Hebrew date
9149  */
9150 ilib.Date.HebrewDate = function(params) {
9151 	this.cal = new ilib.Cal.Hebrew();
9152 	
9153 	if (params) {
9154 		if (params.timezone) {
9155 			this.timezone = params.timezone;
9156 		}
9157 		if (params.locale) {
9158 			this.locale = (typeof(params.locale) === 'string') ? new ilib.Locale(params.locale) : params.locale;
9159 			if (!this.timezone) {
9160 				var li = new ilib.LocaleInfo(this.locale);
9161 				this.timezone = li.getTimeZone(); 
9162 			}
9163 		}
9164 
9165 		if (params.year || params.month || params.day || params.hour ||
9166 				params.minute || params.second || params.millisecond || params.parts ) {
9167 			/**
9168 			 * Year in the Hebrew calendar.
9169 			 * @type number
9170 			 */
9171 			this.year = parseInt(params.year, 10) || 0;
9172 
9173 			/**
9174 			 * The month number, ranging from 1 to 13.
9175 			 * @type number
9176 			 */
9177 			this.month = parseInt(params.month, 10) || 1;
9178 
9179 			/**
9180 			 * The day of the month. This ranges from 1 to 30.
9181 			 * @type number
9182 			 */
9183 			this.day = parseInt(params.day, 10) || 1;
9184 			
9185 			/**
9186 			 * The hour of the day. This can be a number from 0 to 23, as times are
9187 			 * stored unambiguously in the 24-hour clock.
9188 			 * @type number
9189 			 */
9190 			this.hour = parseInt(params.hour, 10) || 0;
9191 
9192 			if (typeof(params.parts) !== 'undefined') {
9193 				/**
9194 				 * The parts (halaqim) of the hour. This can be a number from 0 to 1079.
9195 				 * @type number
9196 				 */
9197 				this.parts = parseInt(params.parts, 10);
9198 				var seconds = parseInt(params.parts, 10) * 3.333333333333;
9199 				this.minute = Math.floor(seconds / 60);
9200 				seconds -= this.minute * 60;
9201 				this.second = Math.floor(seconds);
9202 				this.millisecond = (seconds - this.second);	
9203 			} else {
9204 				/**
9205 				 * The minute of the hours. Ranges from 0 to 59.
9206 				 * @type number
9207 				 */
9208 				this.minute = parseInt(params.minute, 10) || 0;
9209 	
9210 				/**
9211 				 * The second of the minute. Ranges from 0 to 59.
9212 				 * @type number
9213 				 */
9214 				this.second = parseInt(params.second, 10) || 0;
9215 	
9216 				/**
9217 				 * The millisecond of the second. Ranges from 0 to 999.
9218 				 * @type number
9219 				 */
9220 				this.millisecond = parseInt(params.millisecond, 10) || 0;
9221 			}
9222 				
9223 			/**
9224 			 * The day of the year. Ranges from 1 to 383.
9225 			 * @type number
9226 			 */
9227 			this.dayOfYear = parseInt(params.dayOfYear, 10);
9228 			
9229 			if (typeof(params.dst) === 'boolean') {
9230 				this.dst = params.dst;
9231 			}
9232 			
9233 			this.rd = this.newRd(this);
9234 			
9235 			// add the time zone offset to the rd to convert to UTC
9236 			if (!this.tz) {
9237 				this.tz = new ilib.TimeZone({id: this.timezone});
9238 			}
9239 			// getOffsetMillis requires that this.year, this.rd, and this.dst 
9240 			// are set in order to figure out which time zone rules apply and 
9241 			// what the offset is at that point in the year
9242 			this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
9243 			if (this.offset !== 0) {
9244 				this.rd = this.newRd({
9245 					rd: this.rd.getRataDie() - this.offset
9246 				});
9247 			}
9248 		}
9249 	} 
9250 	
9251 	if (!this.rd) {
9252 		this.rd = this.newRd(params);
9253 		this._calcDateComponents();
9254 	}
9255 };
9256 
9257 ilib.Date.HebrewDate.prototype = new ilib.Date({noinstance: true});
9258 ilib.Date.HebrewDate.prototype.parent = ilib.Date;
9259 ilib.Date.HebrewDate.prototype.constructor = ilib.Date.HebrewDate;
9260 
9261 /**
9262  * the cumulative lengths of each month for a non-leap year, without new years corrections
9263  * @private
9264  * @const
9265  * @type Array.<number>
9266  */
9267 ilib.Date.HebrewDate.cumMonthLengths = [
9268 	176,  /* Nisan */
9269 	206,  /* Iyyar */
9270 	235,  /* Sivan */
9271 	265,  /* Tammuz */
9272 	294,  /* Av */
9273 	324,  /* Elul */
9274 	0,    /* Tishri - Jewish New Year (Rosh HaShanah) starts in month 7 */
9275 	30,   /* Heshvan */
9276 	59,   /* Kislev */
9277 	88,   /* Teveth */
9278 	117,  /* Shevat */
9279 	147   /* Adar I */
9280 ];
9281 
9282 /**
9283  * the cumulative lengths of each month for a non-leap year, without new years corrections,
9284  * that can be used in reverse to map days to months
9285  * @private
9286  * @const
9287  * @type Array.<number>
9288  */
9289 ilib.Date.HebrewDate.cumMonthLengthsReverse = [
9290 //  [days, monthnumber],                                                
9291 	[0,   7],  /* Tishri - Jewish New Year (Rosh HaShanah) starts in month 7 */
9292 	[30,  8],  /* Heshvan */
9293 	[59,  9],  /* Kislev */
9294 	[88,  10], /* Teveth */
9295 	[117, 11], /* Shevat */
9296 	[147, 12], /* Adar I */
9297 	[176, 1],  /* Nisan */
9298 	[206, 2],  /* Iyyar */
9299 	[235, 3],  /* Sivan */
9300 	[265, 4],  /* Tammuz */
9301 	[294, 5],  /* Av */
9302 	[324, 6],  /* Elul */
9303 	[354, 7]   /* end of year sentinel value */
9304 ];
9305 
9306 /**
9307  * the cumulative lengths of each month for a leap year, without new years corrections 
9308  * @private
9309  * @const
9310  * @type Array.<number>
9311  */
9312 ilib.Date.HebrewDate.cumMonthLengthsLeap = [
9313 	206,  /* Nisan */
9314 	236,  /* Iyyar */
9315 	265,  /* Sivan */
9316 	295,  /* Tammuz */
9317 	324,  /* Av */
9318 	354,  /* Elul */
9319 	0,    /* Tishri - Jewish New Year (Rosh HaShanah) starts in month 7 */
9320 	30,   /* Heshvan */
9321 	59,   /* Kislev */
9322 	88,   /* Teveth */
9323 	117,  /* Shevat */
9324 	147,  /* Adar I */
9325 	177   /* Adar II */
9326 ];
9327 
9328 /**
9329  * the cumulative lengths of each month for a leap year, without new years corrections
9330  * that can be used in reverse to map days to months 
9331  * 
9332  * @private
9333  * @const
9334  * @type Array.<number>
9335  */
9336 ilib.Date.HebrewDate.cumMonthLengthsLeapReverse = [
9337 //  [days, monthnumber],                                                
9338 	[0,   7],  /* Tishri - Jewish New Year (Rosh HaShanah) starts in month 7 */
9339 	[30,  8],  /* Heshvan */
9340 	[59,  9],  /* Kislev */
9341 	[88,  10], /* Teveth */
9342 	[117, 11], /* Shevat */
9343 	[147, 12], /* Adar I */
9344 	[177, 13], /* Adar II */
9345 	[206, 1],  /* Nisan */
9346 	[236, 2],  /* Iyyar */
9347 	[265, 3],  /* Sivan */
9348 	[295, 4],  /* Tammuz */
9349 	[324, 5],  /* Av */
9350 	[354, 6],  /* Elul */
9351 	[384, 7]   /* end of year sentinel value */
9352 ];
9353 
9354 /**
9355  * Number of days difference between RD 0 of the Hebrew calendar 
9356  * (Jan 1, 1 Gregorian = JD 1721057.5) and RD 0 of the Hebrew calendar
9357  * (September 7, -3760 Gregorian = JD 347997.25)
9358  * @private
9359  * @const
9360  * @type number
9361  */
9362 ilib.Date.HebrewDate.GregorianDiff = 1373060.25;
9363 
9364 /**
9365  * Return a new RD for this date type using the given params.
9366  * @private
9367  * @param {Object=} params the parameters used to create this rata die instance
9368  * @returns {ilib.Date.RataDie} the new RD instance for the given params
9369  */
9370 ilib.Date.HebrewDate.prototype.newRd = function (params) {
9371 	return new ilib.Date.HebrewRataDie(params);
9372 };
9373 
9374 /**
9375  * Return the year for the given RD
9376  * @protected
9377  * @param {number} rd RD to calculate from 
9378  * @returns {number} the year for the RD
9379  */
9380 ilib.Date.HebrewDate.prototype._calcYear = function(rd) {
9381 	var year, approximation, nextNewYear;
9382 	
9383 	// divide by the average number of days per year in the Hebrew calendar
9384 	// to approximate the year, then tweak it to get the real year
9385 	approximation = Math.floor(rd / 365.246822206) + 1;
9386 	
9387 	// console.log("HebrewDate._calcYear: approx is " + approximation);
9388 	
9389 	// search forward from approximation-1 for the year that actually contains this rd
9390 	year = approximation;
9391 	nextNewYear = ilib.Cal.Hebrew.newYear(year);
9392 	while (rd >= nextNewYear) {
9393 		year++;
9394 		nextNewYear = ilib.Cal.Hebrew.newYear(year);
9395 	}
9396 	return year - 1;
9397 };
9398 
9399 /**
9400  * Calculate date components for the given RD date.
9401  * @protected
9402  */
9403 ilib.Date.HebrewDate.prototype._calcDateComponents = function () {
9404 	var remainder,
9405 		i,
9406 		table,
9407 		target,
9408 		rd = this.rd.getRataDie();
9409 	
9410 	// console.log("HebrewDate.calcComponents: calculating for rd " + rd);
9411 
9412 	if (typeof(this.offset) === "undefined") {
9413 		this.year = this._calcYear(rd);
9414 		
9415 		// now offset the RD by the time zone, then recalculate in case we were 
9416 		// near the year boundary
9417 		if (!this.tz) {
9418 			this.tz = new ilib.TimeZone({id: this.timezone});
9419 		}
9420 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
9421 	}
9422 
9423 	if (this.offset !== 0) {
9424 		rd += this.offset;
9425 		this.year = this._calcYear(rd);
9426 	}
9427 	
9428 	// console.log("HebrewDate.calcComponents: year is " + this.year + " with starting rd " + thisNewYear);
9429 	
9430 	remainder = rd - ilib.Cal.Hebrew.newYear(this.year);
9431 	// console.log("HebrewDate.calcComponents: remainder is " + remainder);
9432 
9433 	// take out new years corrections so we get the right month when we look it up in the table
9434 	if (remainder >= 59) {
9435 		if (remainder >= 88) {
9436 			if (ilib.Cal.Hebrew.longKislev(this.year)) {
9437 				remainder--;
9438 			}
9439 		}
9440 		if (ilib.Cal.Hebrew.longHeshvan(this.year)) {
9441 			remainder--;
9442 		}
9443 	}
9444 	
9445 	// console.log("HebrewDate.calcComponents: after new years corrections, remainder is " + remainder);
9446 	
9447 	table = this.cal.isLeapYear(this.year) ? 
9448 			ilib.Date.HebrewDate.cumMonthLengthsLeapReverse :
9449 			ilib.Date.HebrewDate.cumMonthLengthsReverse;
9450 	
9451 	i = 0;
9452 	target = Math.floor(remainder);
9453 	while (i+1 < table.length && target >= table[i+1][0]) {
9454 		i++;
9455 	}
9456 	
9457 	this.month = table[i][1];
9458 	// console.log("HebrewDate.calcComponents: remainder is " + remainder);
9459 	remainder -= table[i][0];
9460 	
9461 	// console.log("HebrewDate.calcComponents: month is " + this.month + " and remainder is " + remainder);
9462 	
9463 	this.day = Math.floor(remainder);
9464 	remainder -= this.day;
9465 	this.day++; // days are 1-based
9466 	
9467 	// console.log("HebrewDate.calcComponents: day is " + this.day + " and remainder is " + remainder);
9468 
9469 	// now convert to milliseconds for the rest of the calculation
9470 	remainder = Math.round(remainder * 86400000);
9471 	
9472 	this.hour = Math.floor(remainder/3600000);
9473 	remainder -= this.hour * 3600000;
9474 	
9475 	// the hours from 0 to 6 are actually 18:00 to midnight of the previous
9476 	// gregorian day, so we have to adjust for that
9477 	if (this.hour >= 6) {
9478 		this.hour -= 6;
9479 	} else {
9480 		this.hour += 18;
9481 	}
9482 		
9483 	this.minute = Math.floor(remainder/60000);
9484 	remainder -= this.minute * 60000;
9485 	
9486 	this.second = Math.floor(remainder/1000);
9487 	remainder -= this.second * 1000;
9488 	
9489 	this.millisecond = Math.floor(remainder);
9490 };
9491 
9492 /**
9493  * Return the day of the week of this date. The day of the week is encoded
9494  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
9495  * 
9496  * @return {number} the day of the week
9497  */
9498 ilib.Date.HebrewDate.prototype.getDayOfWeek = function() {
9499 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
9500 	return ilib.mod(rd+1, 7);
9501 };
9502 
9503 /**
9504  * Get the Halaqim (parts) of an hour. There are 1080 parts in an hour, which means
9505  * each part is 3.33333333 seconds long. This means the number returned may not
9506  * be an integer.
9507  * 
9508  * @return {number} the halaqim parts of the current hour
9509  */
9510 ilib.Date.HebrewDate.prototype.getHalaqim = function() {
9511 	if (this.parts < 0) {
9512 		// convert to ms first, then to parts
9513 		var h = this.minute * 60000 + this.second * 1000 + this.millisecond;
9514 		this.parts = (h * 0.0003);
9515 	}
9516 	return this.parts;
9517 };
9518 
9519 /**
9520  * Return the rd number of the first Sunday of the given ISO year.
9521  * @protected
9522  * @return the rd of the first Sunday of the ISO year
9523  */
9524 ilib.Date.HebrewDate.prototype.firstSunday = function (year) {
9525 	var tishri1 = this.newRd({
9526 		year: year,
9527 		month: 7,
9528 		day: 1,
9529 		hour: 18,
9530 		minute: 0,
9531 		second: 0,
9532 		millisecond: 0,
9533 		cal: this.cal
9534 	});
9535 	var firstThu = this.newRd({
9536 		rd: tishri1.onOrAfter(4),
9537 		cal: this.cal
9538 	});
9539 	return firstThu.before(0);
9540 };
9541 
9542 /**
9543  * Return the ordinal day of the year. Days are counted from 1 and proceed linearly up to 
9544  * 385, regardless of months or weeks, etc. That is, Tishri 1st is day 1, and 
9545  * Elul 29 is 385 for a leap year with a long Heshvan and long Kislev.
9546  * @return {number} the ordinal day of the year
9547  */
9548 ilib.Date.HebrewDate.prototype.getDayOfYear = function() {
9549 	var table = this.cal.isLeapYear(this.year) ? 
9550 				ilib.Date.HebrewDate.cumMonthLengthsLeap : 
9551 				ilib.Date.HebrewDate.cumMonthLengths;
9552 	var days = table[this.month-1];
9553 	if ((this.month < 7 || this.month > 8) && ilib.Cal.Hebrew.longHeshvan(this.year)) {
9554 		days++;
9555 	}
9556 	if ((this.month < 7 || this.month > 9) && ilib.Cal.Hebrew.longKislev(this.year)) {
9557 		days++;
9558 	}
9559 
9560 	return days + this.day;
9561 };
9562 
9563 /**
9564  * Return the ordinal number of the week within the month. The first week of a month is
9565  * the first one that contains 4 or more days in that month. If any days precede this
9566  * first week, they are marked as being in week 0. This function returns values from 0
9567  * through 6.<p>
9568  * 
9569  * The locale is a required parameter because different locales that use the same 
9570  * Hebrew calendar consider different days of the week to be the beginning of
9571  * the week. This can affect the week of the month in which some days are located.
9572  * 
9573  * @param {ilib.Locale|string} locale the locale or locale spec to use when figuring out 
9574  * the first day of the week
9575  * @return {number} the ordinal number of the week within the current month
9576  */
9577 ilib.Date.HebrewDate.prototype.getWeekOfMonth = function(locale) {
9578 	var li = new ilib.LocaleInfo(locale),
9579 		first = this.newRd({
9580 			year: this.year,
9581 			month: this.month,
9582 			day: 1,
9583 			hour: 18,
9584 			minute: 0,
9585 			second: 0,
9586 			millisecond: 0
9587 		}),
9588 		rd = this.rd.getRataDie(),
9589 		weekStart = first.onOrAfter(li.getFirstDayOfWeek());
9590 	
9591 	if (weekStart - first.getRataDie() > 3) {
9592 		// if the first week has 4 or more days in it of the current month, then consider
9593 		// that week 1. Otherwise, it is week 0. To make it week 1, move the week start
9594 		// one week earlier.
9595 		weekStart -= 7;
9596 	}
9597 	return (rd < weekStart) ? 0 : Math.floor((rd - weekStart) / 7) + 1;
9598 };
9599 
9600 /**
9601  * Return the era for this date as a number. The value for the era for Hebrew 
9602  * calendars is -1 for "before the Hebrew era" and 1 for "the Hebrew era". 
9603  * Hebrew era dates are any date after Tishri 1, 1, which is the same as
9604  * September 7, 3760 BC in the Gregorian calendar. 
9605  * 
9606  * @return {number} 1 if this date is in the Hebrew era, -1 if it is before the 
9607  * Hebrew era 
9608  */
9609 ilib.Date.HebrewDate.prototype.getEra = function() {
9610 	return (this.year < 1) ? -1 : 1;
9611 };
9612 
9613 /**
9614  * Return the name of the calendar that governs this date.
9615  * 
9616  * @return {string} a string giving the name of the calendar
9617  */
9618 ilib.Date.HebrewDate.prototype.getCalendar = function() {
9619 	return "hebrew";
9620 };
9621 
9622 // register with the factory method
9623 ilib.Date._constructors["hebrew"] = ilib.Date.HebrewDate;
9624 /*
9625  * islamic.js - Represent a Islamic calendar object.
9626  * 
9627  * Copyright © 2012-2014, JEDLSoft
9628  *
9629  * Licensed under the Apache License, Version 2.0 (the "License");
9630  * you may not use this file except in compliance with the License.
9631  * You may obtain a copy of the License at
9632  *
9633  *     http://www.apache.org/licenses/LICENSE-2.0
9634  *
9635  * Unless required by applicable law or agreed to in writing, software
9636  * distributed under the License is distributed on an "AS IS" BASIS,
9637  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9638  *
9639  * See the License for the specific language governing permissions and
9640  * limitations under the License.
9641  */
9642 
9643 
9644 /* !depends calendar.js locale.js date.js julianday.js util/utils.js util/math.js */
9645 
9646 /**
9647  * @class
9648  * Construct a new Islamic calendar object. This class encodes information about
9649  * the civil Islamic calendar. The civil Islamic calendar is a tabular islamic 
9650  * calendar where the dates are calculated by arithmetic rules. This differs from 
9651  * the religious Islamic calendar which is used to mark the beginning of particular 
9652  * holidays. The religious calendar depends on the first sighting of the new 
9653  * crescent moon to determine the first day of the new month. Because humans and 
9654  * weather are both involved, the actual time of sighting varies, so it is not 
9655  * really possible to precalculate the religious calendar. Certain groups, such 
9656  * as the Islamic Society of North America, decreed in in 2007 that they will use
9657  * a calendar based on calculations rather than observations to determine the 
9658  * beginning of lunar months, and therefore the dates of holidays.<p>
9659  * 
9660  * Depends directive: !depends islamic.js
9661  * 
9662  * @constructor
9663  * @implements ilib.Cal
9664  */
9665 ilib.Cal.Islamic = function() {
9666 	this.type = "islamic";
9667 };
9668 
9669 /**
9670  * the lengths of each month 
9671  * @private
9672  * @const
9673  * @type Array.<number>
9674  */
9675 ilib.Cal.Islamic.monthLengths = [
9676 	30,  /* Muharram */
9677 	29,  /* Saffar */
9678 	30,  /* Rabi'I */
9679 	29,  /* Rabi'II */
9680 	30,  /* Jumada I */
9681 	29,  /* Jumada II */
9682 	30,  /* Rajab */
9683 	29,  /* Sha'ban */
9684 	30,  /* Ramadan */
9685 	29,  /* Shawwal */
9686 	30,  /* Dhu al-Qa'da */
9687 	29   /* Dhu al-Hijja */
9688 ];
9689 
9690 
9691 /**
9692  * Return the number of months in the given year. The number of months in a year varies
9693  * for luni-solar calendars because in some years, an extra month is needed to extend the 
9694  * days in a year to an entire solar year. The month is represented as a 1-based number
9695  * where 1=first month, 2=second month, etc.
9696  * 
9697  * @param {number} year a year for which the number of months is sought
9698  */
9699 ilib.Cal.Islamic.prototype.getNumMonths = function(year) {
9700 	return 12;
9701 };
9702 
9703 /**
9704  * Return the number of days in a particular month in a particular year. This function
9705  * can return a different number for a month depending on the year because of things
9706  * like leap years.
9707  *
9708  * @param {number} month the month for which the length is sought
9709  * @param {number} year the year within which that month can be found
9710  * @return {number} the number of days within the given month in the given year
9711  */
9712 ilib.Cal.Islamic.prototype.getMonLength = function(month, year) {
9713 	if (month !== 12) {
9714 		return ilib.Cal.Islamic.monthLengths[month-1];
9715 	} else {
9716 		return this.isLeapYear(year) ? 30 : 29;
9717 	}
9718 };
9719 
9720 /**
9721  * Return true if the given year is a leap year in the Islamic calendar.
9722  * The year parameter may be given as a number, or as a IslamicDate object.
9723  * @param {number} year the year for which the leap year information is being sought
9724  * @return {boolean} true if the given year is a leap year
9725  */
9726 ilib.Cal.Islamic.prototype.isLeapYear = function(year) {
9727 	return (ilib.mod((14 + 11 * year), 30) < 11);
9728 };
9729 
9730 /**
9731  * Return the type of this calendar.
9732  * 
9733  * @return {string} the name of the type of this calendar 
9734  */
9735 ilib.Cal.Islamic.prototype.getType = function() {
9736 	return this.type;
9737 };
9738 
9739 /**
9740  * Return a date instance for this calendar type using the given
9741  * options.
9742  * @param {Object} options options controlling the construction of 
9743  * the date instance
9744  * @return {ilib.Date} a date appropriate for this calendar type
9745  */
9746 ilib.Cal.Islamic.prototype.newDateInstance = function (options) {
9747 	return new ilib.Date.IslamicDate(options);
9748 };
9749 
9750 /*register this calendar for the factory method */
9751 ilib.Cal._constructors["islamic"] = ilib.Cal.Islamic;
9752 
9753 /*
9754  * util/search.js - Misc search utility routines
9755  * 
9756  * Copyright © 2013, JEDLSoft
9757  *
9758  * Licensed under the Apache License, Version 2.0 (the "License");
9759  * you may not use this file except in compliance with the License.
9760  * You may obtain a copy of the License at
9761  *
9762  *     http://www.apache.org/licenses/LICENSE-2.0
9763  *
9764  * Unless required by applicable law or agreed to in writing, software
9765  * distributed under the License is distributed on an "AS IS" BASIS,
9766  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9767  *
9768  * See the License for the specific language governing permissions and
9769  * limitations under the License.
9770  */
9771 
9772 // !depends ilibglobal.js
9773 
9774 /**
9775  * Binary search a sorted array for a particular target value.
9776  * If the exact value is not found, it returns the index of the smallest 
9777  * entry that is greater than the given target value.<p> 
9778  * 
9779  * The comparator
9780  * parameter is a function that knows how to compare elements of the 
9781  * array and the target. The function should return a value greater than 0
9782  * if the array element is greater than the target, a value less than 0 if
9783  * the array element is less than the target, and 0 if the array element 
9784  * and the target are equivalent.<p>
9785  * 
9786  * If the comparator function is not specified, this function assumes
9787  * the array and the target are numeric values and should be compared 
9788  * as such.<p>
9789  * 
9790  * Depends directive: !depends utils.js
9791  * 
9792  * @static
9793  * @param {*} target element being sought 
9794  * @param {Array} arr the array being searched
9795  * @param {?function(*,*)=} comparator a comparator that is appropriate for comparing two entries
9796  * in the array  
9797  * @return the index of the array into which the value would fit if 
9798  * inserted, or -1 if given array is not an array or the target is not 
9799  * a number
9800  */
9801 ilib.bsearch = function(target, arr, comparator) {
9802 	if (typeof(arr) === 'undefined' || !arr || typeof(target) === 'undefined') {
9803 		return -1;
9804 	}
9805 	
9806 	var high = arr.length - 1,
9807 		low = 0,
9808 		mid = 0,
9809 		value,
9810 		cmp = comparator || ilib.bsearch.numbers;
9811 	
9812 	while (low <= high) {
9813 		mid = Math.floor((high+low)/2);
9814 		value = cmp(arr[mid], target);
9815 		if (value > 0) {
9816 			high = mid - 1;
9817 		} else if (value < 0) {
9818 			low = mid + 1;
9819 		} else {
9820 			return mid;
9821 		}
9822 	}
9823 	
9824 	return low;
9825 };
9826 
9827 /**
9828  * Returns whether or not the given element is greater than, less than,
9829  * or equal to the given target.<p>
9830  * 
9831  * @private
9832  * @static
9833  * @param {number} element the element being tested
9834  * @param {number} target the target being sought
9835  */
9836 ilib.bsearch.numbers = function(element, target) {
9837 	return element - target;
9838 };
9839 
9840 /**
9841  * Do a bisection search of a function for a particular target value.<p> 
9842  * 
9843  * The function to search is a function that takes a numeric parameter, 
9844  * does calculations, and returns gives a numeric result. The 
9845  * function should should be smooth and not have any discontinuities 
9846  * between the low and high values of the parameter.
9847  *  
9848  * Depends directive: !depends utils.js
9849  * 
9850  * @static
9851  * @param {number} target value being sought
9852  * @param {number} low the lower bounds to start searching
9853  * @param {number} high the upper bounds to start searching
9854  * @param {number} precision minimum precision to support. Use 0 if you want to use the default.
9855  * @param {?function(number)=} func function to search 
9856  * @return an approximation of the input value to the function that gives the desired
9857  * target output value, correct to within the error range of Javascript floating point 
9858  * arithmetic, or NaN if there was some error
9859  */
9860 ilib.bisectionSearch = function(target, low, high, precision, func) {
9861 	if (typeof(target) !== 'number' || 
9862 			typeof(low) !== 'number' || 
9863 			typeof(high) !== 'number' || 
9864 			typeof(func) !== 'function') {
9865 		return NaN;
9866 	}
9867 	
9868 	var mid = 0,
9869 		value,
9870 		pre = precision > 0 ? precision : 1e-13;
9871 	
9872 	function compareSignificantDigits(a, b) {
9873 		var leftParts = a.toExponential().split('e');
9874 		var rightParts = b.toExponential().split('e');
9875 		var left = new Number(leftParts[0]);
9876 		var right = new Number(rightParts[0]);
9877 		
9878 		return leftParts[1] === rightParts[1] && Math.abs(left - right) < pre; 
9879 	}
9880 	
9881 	do {
9882 		mid = (high+low)/2;
9883 		value = func(mid);
9884 		if (value > target) {
9885 			high = mid;
9886 		} else if (value < target) {
9887 			low = mid;
9888 		}
9889 	} while (high - low > pre);
9890 	
9891 	return mid;
9892 };
9893 
9894 
9895 /*
9896  * islamicdate.js - Represent a date in the Islamic calendar
9897  * 
9898  * Copyright © 2012-2014, JEDLSoft
9899  *
9900  * Licensed under the Apache License, Version 2.0 (the "License");
9901  * you may not use this file except in compliance with the License.
9902  * You may obtain a copy of the License at
9903  *
9904  *     http://www.apache.org/licenses/LICENSE-2.0
9905  *
9906  * Unless required by applicable law or agreed to in writing, software
9907  * distributed under the License is distributed on an "AS IS" BASIS,
9908  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9909  *
9910  * See the License for the specific language governing permissions and
9911  * limitations under the License.
9912  */
9913 
9914 /* !depends 
9915 date.js 
9916 calendar/islamic.js 
9917 util/utils.js 
9918 util/search.js
9919 util/math.js
9920 localeinfo.js
9921 julianday.js
9922 */
9923 
9924 /**
9925  * @class
9926  * Construct a new Islamic RD date number object. The constructor parameters can 
9927  * contain any of the following properties:
9928  * 
9929  * <ul>
9930  * <li><i>unixtime<i> - sets the time of this instance according to the given 
9931  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
9932  * 
9933  * <li><i>julianday</i> - sets the time of this instance according to the given
9934  * Julian Day instance or the Julian Day given as a float
9935  * 
9936  * <li><i>year</i> - any integer, including 0
9937  * 
9938  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
9939  * 
9940  * <li><i>day</i> - 1 to 31
9941  * 
9942  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
9943  * is always done with an unambiguous 24 hour representation
9944  * 
9945  * <li><i>minute</i> - 0 to 59
9946  * 
9947  * <li><i>second</i> - 0 to 59
9948  * 
9949  * <li><i>millisecond</i> - 0 to 999
9950  * 
9951  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
9952  * </ul>
9953  *
9954  * If the constructor is called with another Islamic date instance instead of
9955  * a parameter block, the other instance acts as a parameter block and its
9956  * settings are copied into the current instance.<p>
9957  * 
9958  * If the constructor is called with no arguments at all or if none of the 
9959  * properties listed above are present, then the RD is calculate based on 
9960  * the current date at the time of instantiation. <p>
9961  * 
9962  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
9963  * specified in the params, it is assumed that they have the smallest possible
9964  * value in the range for the property (zero or one).<p>
9965  * 
9966  * Depends directive: !depends islamicdate.js
9967  * 
9968  * @private
9969  * @constructor
9970  * @extends ilib.Date.RataDie
9971  * @param {Object=} params parameters that govern the settings and behaviour of this Islamic RD date
9972  */
9973 ilib.Date.IslamicRataDie = function(params) {
9974 	this.cal = params && params.cal || new ilib.Cal.Islamic();
9975 	this.rd = undefined;
9976 	ilib.Date.RataDie.call(this, params);
9977 };
9978 
9979 ilib.Date.IslamicRataDie.prototype = new ilib.Date.RataDie();
9980 ilib.Date.IslamicRataDie.prototype.parent = ilib.Date.RataDie;
9981 ilib.Date.IslamicRataDie.prototype.constructor = ilib.Date.IslamicRataDie;
9982 
9983 /**
9984  * The difference between a zero Julian day and the first Islamic date
9985  * of Friday, July 16, 622 CE Julian. 
9986  * @private
9987  * @const
9988  * @type number
9989  */
9990 ilib.Date.IslamicRataDie.prototype.epoch = 1948439.5;
9991 
9992 /**
9993  * Calculate the Rata Die (fixed day) number of the given date from the
9994  * date components.
9995  *
9996  * @protected
9997  * @param {Object} date the date components to calculate the RD from
9998  */
9999 ilib.Date.IslamicRataDie.prototype._setDateComponents = function(date) {
10000 	var days = (date.year - 1) * 354 +
10001 		Math.ceil(29.5 * (date.month - 1)) +
10002 		date.day +
10003 		Math.floor((3 + 11 * date.year) / 30) - 1;
10004 	var time = (date.hour * 3600000 +
10005 		date.minute * 60000 +
10006 		date.second * 1000 +
10007 		date.millisecond) / 
10008 		86400000; 
10009 	
10010 	//console.log("getRataDie: converting " +  JSON.stringify(date));
10011 	//console.log("getRataDie: days is " +  days);
10012 	//console.log("getRataDie: time is " +  time);
10013 	//console.log("getRataDie: rd is " +  (days + time));
10014 
10015 	this.rd = days + time;
10016 };
10017 	
10018 /**
10019  * @class
10020  * Construct a new civil Islamic date object. The constructor can be called
10021  * with a params object that can contain the following properties:<p>
10022  * 
10023  * <ul>
10024  * <li><i>julianday</i> - the Julian Day to set into this date
10025  * <li><i>year</i> - any integer except 0. Years go from -1 (BCE) to 1 (CE), skipping the zero year
10026  * <li><i>month</i> - 1 to 12, where 1 means Muharram, 2 means Saffar, etc.
10027  * <li><i>day</i> - 1 to 30
10028  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
10029  * is always done with an unambiguous 24 hour representation
10030  * <li><i>minute</i> - 0 to 59
10031  * <li><i>second</i> - 0 to 59
10032  * <li><i>millisecond</i> - 0 to 999
10033  * <li><i>locale</i> - the ilib.TimeZone instance or time zone name as a string 
10034  * of this julian date. The date/time is kept in the local time. The time zone
10035  * is used later if this date is formatted according to a different time zone and
10036  * the difference has to be calculated, or when the date format has a time zone
10037  * component in it.
10038  * <li><i>timezone</i> - the time zone of this instance. If the time zone is not 
10039  * given, it can be inferred from this locale. For locales that span multiple
10040  * time zones, the one with the largest population is chosen as the one that 
10041  * represents the locale. 
10042  * 
10043  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
10044  * </ul>
10045  * 
10046  * If called with another Islamic date argument, the date components of the given
10047  * date are copied into the current one.<p>
10048  * 
10049  * If the constructor is called with no arguments at all or if none of the 
10050  * properties listed above 
10051  * from <i>julianday</i> through <i>millisecond</i> are present, then the date 
10052  * components are 
10053  * filled in with the current date at the time of instantiation. Note that if
10054  * you do not give the time zone when defaulting to the current time and the 
10055  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
10056  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
10057  * Mean Time").<p>
10058  * 
10059  * Depends directive: !depends islamicdate.js
10060  * 
10061  * @constructor
10062  * @extends ilib.Date
10063  * @param {Object=} params parameters that govern the settings and behaviour of this Islamic date
10064  */
10065 ilib.Date.IslamicDate = function(params) {
10066 	this.cal = new ilib.Cal.Islamic();
10067 	
10068 	if (params) {
10069 		if (params.locale) {
10070 			this.locale = (typeof(params.locale) === 'string') ? new ilib.Locale(params.locale) : params.locale;
10071 			var li = new ilib.LocaleInfo(this.locale);
10072 			this.timezone = li.getTimeZone(); 
10073 		}
10074 		if (params.timezone) {
10075 			this.timezone = params.timezone;
10076 		}
10077 		
10078 		if (params.year || params.month || params.day || params.hour ||
10079 				params.minute || params.second || params.millisecond ) {
10080 			/**
10081 			 * Year in the Islamic calendar.
10082 			 * @type number
10083 			 */
10084 			this.year = parseInt(params.year, 10) || 0;
10085 
10086 			/**
10087 			 * The month number, ranging from 1 to 12 (December).
10088 			 * @type number
10089 			 */
10090 			this.month = parseInt(params.month, 10) || 1;
10091 
10092 			/**
10093 			 * The day of the month. This ranges from 1 to 30.
10094 			 * @type number
10095 			 */
10096 			this.day = parseInt(params.day, 10) || 1;
10097 			
10098 			/**
10099 			 * The hour of the day. This can be a number from 0 to 23, as times are
10100 			 * stored unambiguously in the 24-hour clock.
10101 			 * @type number
10102 			 */
10103 			this.hour = parseInt(params.hour, 10) || 0;
10104 
10105 			/**
10106 			 * The minute of the hours. Ranges from 0 to 59.
10107 			 * @type number
10108 			 */
10109 			this.minute = parseInt(params.minute, 10) || 0;
10110 
10111 			/**
10112 			 * The second of the minute. Ranges from 0 to 59.
10113 			 * @type number
10114 			 */
10115 			this.second = parseInt(params.second, 10) || 0;
10116 
10117 			/**
10118 			 * The millisecond of the second. Ranges from 0 to 999.
10119 			 * @type number
10120 			 */
10121 			this.millisecond = parseInt(params.millisecond, 10) || 0;
10122 			
10123 			/**
10124 			 * The day of the year. Ranges from 1 to 355.
10125 			 * @type number
10126 			 */
10127 			this.dayOfYear = parseInt(params.dayOfYear, 10);
10128 
10129 			if (typeof(params.dst) === 'boolean') {
10130 				this.dst = params.dst;
10131 			}
10132 			
10133 			this.rd = this.newRd(this);
10134 			
10135 			// add the time zone offset to the rd to convert to UTC
10136 			if (!this.tz) {
10137 				this.tz = new ilib.TimeZone({id: this.timezone});
10138 			}
10139 			// getOffsetMillis requires that this.year, this.rd, and this.dst 
10140 			// are set in order to figure out which time zone rules apply and 
10141 			// what the offset is at that point in the year
10142 			this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
10143 			if (this.offset !== 0) {
10144 				this.rd = this.newRd({
10145 					rd: this.rd.getRataDie() - this.offset
10146 				});
10147 			}
10148 		}
10149 	}
10150 
10151 	if (!this.rd) {
10152 		this.rd = this.newRd(params);
10153 		this._calcDateComponents();
10154 	}
10155 };
10156 
10157 ilib.Date.IslamicDate.prototype = new ilib.Date({noinstance: true});
10158 ilib.Date.IslamicDate.prototype.parent = ilib.Date;
10159 ilib.Date.IslamicDate.prototype.constructor = ilib.Date.IslamicDate;
10160 
10161 /**
10162  * the cumulative lengths of each month, for a non-leap year 
10163  * @private
10164  * @const
10165  * @type Array.<number>
10166  */
10167 ilib.Date.IslamicDate.cumMonthLengths = [
10168 	0,  /* Muharram */
10169 	30,  /* Saffar */
10170 	59,  /* Rabi'I */
10171 	89,  /* Rabi'II */
10172 	118,  /* Jumada I */
10173 	148,  /* Jumada II */
10174 	177,  /* Rajab */
10175 	207,  /* Sha'ban */
10176 	236,  /* Ramadan */
10177 	266,  /* Shawwal */
10178 	295,  /* Dhu al-Qa'da */
10179 	325,  /* Dhu al-Hijja */
10180 	354
10181 ];
10182 
10183 /**
10184  * Number of days difference between RD 0 of the Gregorian calendar and
10185  * RD 0 of the Islamic calendar. 
10186  * @private
10187  * @const
10188  * @type number
10189  */
10190 ilib.Date.IslamicDate.GregorianDiff = 227015;
10191 
10192 /**
10193  * Return a new RD for this date type using the given params.
10194  * @protected
10195  * @param {Object=} params the parameters used to create this rata die instance
10196  * @returns {ilib.Date.RataDie} the new RD instance for the given params
10197  */
10198 ilib.Date.IslamicDate.prototype.newRd = function (params) {
10199 	return new ilib.Date.IslamicRataDie(params);
10200 };
10201 
10202 /**
10203  * Return the year for the given RD
10204  * @protected
10205  * @param {number} rd RD to calculate from 
10206  * @returns {number} the year for the RD
10207  */
10208 ilib.Date.IslamicDate.prototype._calcYear = function(rd) {
10209 	return Math.floor((30 * rd + 10646) / 10631);
10210 };
10211 
10212 /**
10213  * Calculate date components for the given RD date.
10214  * @protected
10215  */
10216 ilib.Date.IslamicDate.prototype._calcDateComponents = function () {
10217 	var remainder,
10218 		rd = this.rd.getRataDie();
10219 	
10220 	this.year = this._calcYear(rd);
10221 
10222 	if (typeof(this.offset) === "undefined") {
10223 		this.year = this._calcYear(rd);
10224 		
10225 		// now offset the RD by the time zone, then recalculate in case we were 
10226 		// near the year boundary
10227 		if (!this.tz) {
10228 			this.tz = new ilib.TimeZone({id: this.timezone});
10229 		}
10230 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
10231 	}
10232 
10233 	if (this.offset !== 0) {
10234 		rd += this.offset;
10235 		this.year = this._calcYear(rd);
10236 	}
10237 
10238 	//console.log("IslamicDate.calcComponent: calculating for rd " + rd);
10239 	//console.log("IslamicDate.calcComponent: year is " + ret.year);
10240 	var yearStart = this.newRd({
10241 		year: this.year,
10242 		month: 1,
10243 		day: 1,
10244 		hour: 0,
10245 		minute: 0,
10246 		second: 0,
10247 		millisecond: 0
10248 	});
10249 	remainder = rd - yearStart.getRataDie() + 1;
10250 	
10251 	this.dayOfYear = remainder;
10252 	
10253 	//console.log("IslamicDate.calcComponent: remainder is " + remainder);
10254 	
10255 	this.month = ilib.bsearch(remainder, ilib.Date.IslamicDate.cumMonthLengths);
10256 	remainder -= ilib.Date.IslamicDate.cumMonthLengths[this.month-1];
10257 
10258 	//console.log("IslamicDate.calcComponent: month is " + this.month + " and remainder is " + remainder);
10259 	
10260 	this.day = Math.floor(remainder);
10261 	remainder -= this.day;
10262 
10263 	//console.log("IslamicDate.calcComponent: day is " + this.day + " and remainder is " + remainder);
10264 
10265 	// now convert to milliseconds for the rest of the calculation
10266 	remainder = Math.round(remainder * 86400000);
10267 	
10268 	this.hour = Math.floor(remainder/3600000);
10269 	remainder -= this.hour * 3600000;
10270 	
10271 	this.minute = Math.floor(remainder/60000);
10272 	remainder -= this.minute * 60000;
10273 	
10274 	this.second = Math.floor(remainder/1000);
10275 	remainder -= this.second * 1000;
10276 	
10277 	this.millisecond = remainder;
10278 };
10279 
10280 /**
10281  * Return the day of the week of this date. The day of the week is encoded
10282  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
10283  * 
10284  * @return {number} the day of the week
10285  */
10286 ilib.Date.IslamicDate.prototype.getDayOfWeek = function() {
10287 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
10288 	return ilib.mod(rd-2, 7);
10289 };
10290 
10291 /**
10292  * Return the ordinal day of the year. Days are counted from 1 and proceed linearly up to 
10293  * 354 or 355, regardless of months or weeks, etc. That is, Muharran 1st is day 1, and 
10294  * Dhu al-Hijja 29 is 354.
10295  * @return {number} the ordinal day of the year
10296  */
10297 ilib.Date.IslamicDate.prototype.getDayOfYear = function() {
10298 	return ilib.Date.IslamicDate.cumMonthLengths[this.month-1] + this.day;
10299 };
10300 
10301 /**
10302  * Return the era for this date as a number. The value for the era for Islamic 
10303  * calendars is -1 for "before the Islamic era" and 1 for "the Islamic era". 
10304  * Islamic era dates are any date after Muharran 1, 1, which is the same as
10305  * July 16, 622 CE in the Gregorian calendar. 
10306  * 
10307  * @return {number} 1 if this date is in the common era, -1 if it is before the 
10308  * common era 
10309  */
10310 ilib.Date.IslamicDate.prototype.getEra = function() {
10311 	return (this.year < 1) ? -1 : 1;
10312 };
10313 
10314 /**
10315  * Return the name of the calendar that governs this date.
10316  * 
10317  * @return {string} a string giving the name of the calendar
10318  */
10319 ilib.Date.IslamicDate.prototype.getCalendar = function() {
10320 	return "islamic";
10321 };
10322 
10323 //register with the factory method
10324 ilib.Date._constructors["islamic"] = ilib.Date.IslamicDate;
10325 /*
10326  * julian.js - Represent a Julian calendar object.
10327  * 
10328  * Copyright © 2012-2014, JEDLSoft
10329  *
10330  * Licensed under the Apache License, Version 2.0 (the "License");
10331  * you may not use this file except in compliance with the License.
10332  * You may obtain a copy of the License at
10333  *
10334  *     http://www.apache.org/licenses/LICENSE-2.0
10335  *
10336  * Unless required by applicable law or agreed to in writing, software
10337  * distributed under the License is distributed on an "AS IS" BASIS,
10338  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10339  *
10340  * See the License for the specific language governing permissions and
10341  * limitations under the License.
10342  */
10343 
10344 
10345 /* !depends calendar.js locale.js date.js julianday.js util/utils.js util/math.js */
10346 
10347 /**
10348  * @class
10349  * Construct a new Julian calendar object. This class encodes information about
10350  * a Julian calendar.<p>
10351  * 
10352  * Depends directive: !depends julian.js
10353  * 
10354  * @constructor
10355  * @implements ilib.Cal
10356  */
10357 ilib.Cal.Julian = function() {
10358 	this.type = "julian";
10359 };
10360 
10361 /* the lengths of each month */
10362 ilib.Cal.Julian.monthLengths = [
10363 	31,  /* Jan */
10364 	28,  /* Feb */
10365 	31,  /* Mar */
10366 	30,  /* Apr */
10367 	31,  /* May */
10368 	30,  /* Jun */
10369 	31,  /* Jul */
10370 	31,  /* Aug */
10371 	30,  /* Sep */
10372 	31,  /* Oct */
10373 	30,  /* Nov */
10374 	31   /* Dec */
10375 ];
10376 
10377 /**
10378  * Return the number of months in the given year. The number of months in a year varies
10379  * for lunar calendars because in some years, an extra month is needed to extend the 
10380  * days in a year to an entire solar year. The month is represented as a 1-based number
10381  * where 1=Jaunary, 2=February, etc. until 12=December.
10382  * 
10383  * @param {number} year a year for which the number of months is sought
10384  */
10385 ilib.Cal.Julian.prototype.getNumMonths = function(year) {
10386 	return 12;
10387 };
10388 
10389 /**
10390  * Return the number of days in a particular month in a particular year. This function
10391  * can return a different number for a month depending on the year because of things
10392  * like leap years.
10393  * 
10394  * @param {number} month the month for which the length is sought
10395  * @param {number} year the year within which that month can be found
10396  * @return {number} the number of days within the given month in the given year
10397  */
10398 ilib.Cal.Julian.prototype.getMonLength = function(month, year) {
10399 	if (month !== 2 || !this.isLeapYear(year)) {
10400 		return ilib.Cal.Julian.monthLengths[month-1];
10401 	} else {
10402 		return 29;
10403 	}
10404 };
10405 
10406 /**
10407  * Return true if the given year is a leap year in the Julian calendar.
10408  * The year parameter may be given as a number, or as a JulDate object.
10409  * @param {number|ilib.Date.JulDate} year the year for which the leap year information is being sought
10410  * @return {boolean} true if the given year is a leap year
10411  */
10412 ilib.Cal.Julian.prototype.isLeapYear = function(year) {
10413 	var y = (typeof(year) === 'number' ? year : year.year);
10414 	return ilib.mod(y, 4) === ((year > 0) ? 0 : 3);
10415 };
10416 
10417 /**
10418  * Return the type of this calendar.
10419  * 
10420  * @return {string} the name of the type of this calendar 
10421  */
10422 ilib.Cal.Julian.prototype.getType = function() {
10423 	return this.type;
10424 };
10425 
10426 /**
10427  * Return a date instance for this calendar type using the given
10428  * options.
10429  * @param {Object} options options controlling the construction of 
10430  * the date instance
10431  * @return {ilib.Date} a date appropriate for this calendar type
10432  */
10433 ilib.Cal.Julian.prototype.newDateInstance = function (options) {
10434 	return new ilib.Date.JulDate(options);
10435 };
10436 
10437 /* register this calendar for the factory method */
10438 ilib.Cal._constructors["julian"] = ilib.Cal.Julian;
10439 /*
10440  * juliandate.js - Represent a date in the Julian calendar
10441  * 
10442  * Copyright © 2012-2014, JEDLSoft
10443  *
10444  * Licensed under the Apache License, Version 2.0 (the "License");
10445  * you may not use this file except in compliance with the License.
10446  * You may obtain a copy of the License at
10447  *
10448  *     http://www.apache.org/licenses/LICENSE-2.0
10449  *
10450  * Unless required by applicable law or agreed to in writing, software
10451  * distributed under the License is distributed on an "AS IS" BASIS,
10452  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10453  *
10454  * See the License for the specific language governing permissions and
10455  * limitations under the License.
10456  */
10457 
10458 /* !depends 
10459 date.js 
10460 calendar/julian.js 
10461 util/utils.js
10462 util/search.js 
10463 util/math.js
10464 localeinfo.js 
10465 julianday.js 
10466 */
10467 
10468 /**
10469  * @class
10470  * Construct a new Julian RD date number object. The constructor parameters can 
10471  * contain any of the following properties:
10472  * 
10473  * <ul>
10474  * <li><i>unixtime<i> - sets the time of this instance according to the given 
10475  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
10476  * 
10477  * <li><i>julianday</i> - sets the time of this instance according to the given
10478  * Julian Day instance or the Julian Day given as a float
10479  * 
10480  * <li><i>year</i> - any integer, including 0
10481  * 
10482  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
10483  * 
10484  * <li><i>day</i> - 1 to 31
10485  * 
10486  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
10487  * is always done with an unambiguous 24 hour representation
10488  * 
10489  * <li><i>minute</i> - 0 to 59
10490  * 
10491  * <li><i>second</i> - 0 to 59
10492  * 
10493  * <li><i>millisecond</i> - 0 to 999
10494  * 
10495  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
10496  * </ul>
10497  *
10498  * If the constructor is called with another Julian date instance instead of
10499  * a parameter block, the other instance acts as a parameter block and its
10500  * settings are copied into the current instance.<p>
10501  * 
10502  * If the constructor is called with no arguments at all or if none of the 
10503  * properties listed above are present, then the RD is calculate based on 
10504  * the current date at the time of instantiation. <p>
10505  * 
10506  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
10507  * specified in the params, it is assumed that they have the smallest possible
10508  * value in the range for the property (zero or one).<p>
10509  * 
10510  * Depends directive: !depends juliandate.js
10511  * 
10512  * @private
10513  * @constructor
10514  * @extends ilib.Date.RataDie
10515  * @param {Object=} params parameters that govern the settings and behaviour of this Julian RD date
10516  */
10517 ilib.Date.JulianRataDie = function(params) {
10518 	this.cal = params && params.cal || new ilib.Cal.Julian();
10519 	this.rd = undefined;
10520 	ilib.Date.RataDie.call(this, params);
10521 };
10522 
10523 ilib.Date.JulianRataDie.prototype = new ilib.Date.RataDie();
10524 ilib.Date.JulianRataDie.prototype.parent = ilib.Date.RataDie;
10525 ilib.Date.JulianRataDie.prototype.constructor = ilib.Date.JulianRataDie;
10526 
10527 /**
10528  * The difference between a zero Julian day and the first Julian date
10529  * of Friday, July 16, 622 CE Julian. 
10530  * @private
10531  * @const
10532  * @type number
10533  */
10534 ilib.Date.JulianRataDie.prototype.epoch = 1721422.5;
10535 
10536 /**
10537  * Calculate the Rata Die (fixed day) number of the given date from the
10538  * date components.
10539  * 
10540  * @protected
10541  * @param {Object} date the date components to calculate the RD from
10542  */
10543 ilib.Date.JulianRataDie.prototype._setDateComponents = function(date) {
10544 	var year = date.year + ((date.year < 0) ? 1 : 0);
10545 	var years = 365 * (year - 1) + Math.floor((year-1)/4);
10546 	var dayInYear = (date.month > 1 ? ilib.Date.JulDate.cumMonthLengths[date.month-1] : 0) +
10547 		date.day +
10548 		(this.cal.isLeapYear(date.year) && date.month > 2 ? 1 : 0);
10549 	var rdtime = (date.hour * 3600000 +
10550 		date.minute * 60000 +
10551 		date.second * 1000 +
10552 		date.millisecond) / 
10553 		86400000;
10554 	
10555 	/*
10556 	console.log("calcRataDie: converting " +  JSON.stringify(parts));
10557 	console.log("getRataDie: year is " +  years);
10558 	console.log("getRataDie: day in year is " +  dayInYear);
10559 	console.log("getRataDie: rdtime is " +  rdtime);
10560 	console.log("getRataDie: rd is " +  (years + dayInYear + rdtime));
10561 	*/
10562 	
10563 	this.rd = years + dayInYear + rdtime;
10564 };
10565 
10566 /**
10567  * @class
10568  * Construct a new date object for the Julian Calendar. The constructor can be called
10569  * with a parameter object that contains any of the following properties:
10570  * 
10571  * <ul>
10572  * <li><i>unixtime<i> - sets the time of this instance according to the given 
10573  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970 (Gregorian).
10574  * <li><i>julianday</i> - the Julian Day to set into this date
10575  * <li><i>year</i> - any integer except 0. Years go from -1 (BCE) to 1 (CE), skipping the zero 
10576  * year which doesn't exist in the Julian calendar
10577  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
10578  * <li><i>day</i> - 1 to 31
10579  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
10580  * is always done with an unambiguous 24 hour representation
10581  * <li><i>minute</i> - 0 to 59
10582  * <li><i>second</i> - 0 to 59
10583  * <li><i>millisecond<i> - 0 to 999
10584  * <li><i>locale</i> - the ilib.TimeZone instance or time zone name as a string 
10585  * of this julian date. The date/time is kept in the local time. The time zone
10586  * is used later if this date is formatted according to a different time zone and
10587  * the difference has to be calculated, or when the date format has a time zone
10588  * component in it.
10589  * <li><i>timezone</i> - the time zone of this instance. If the time zone is not 
10590  * given, it can be inferred from this locale. For locales that span multiple
10591  * time zones, the one with the largest population is chosen as the one that 
10592  * represents the locale. 
10593  * 
10594  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
10595  * </ul>
10596  * 
10597  * NB. The <a href="http://en.wikipedia.org/wiki/Julian_date">Julian Day</a> 
10598  * (ilib.JulianDay) object is a <i>different</i> object than a 
10599  * <a href="http://en.wikipedia.org/wiki/Julian_calendar">date in
10600  * the Julian calendar</a> and the two are not to be confused. The Julian Day 
10601  * object represents time as a number of whole and fractional days since the 
10602  * beginning of the epoch, whereas a date in the Julian 
10603  * calendar is a regular date that signifies year, month, day, etc. using the rules
10604  * of the Julian calendar. The naming of Julian Days and the Julian calendar are
10605  * unfortunately close, and come from history.<p>
10606  *  
10607  * If called with another Julian date argument, the date components of the given
10608  * date are copied into the current one.<p>
10609  * 
10610  * If the constructor is called with no arguments at all or if none of the 
10611  * properties listed above 
10612  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
10613  * components are 
10614  * filled in with the current date at the time of instantiation. Note that if
10615  * you do not give the time zone when defaulting to the current time and the 
10616  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
10617  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
10618  * Mean Time").<p>
10619  * 
10620  * Depends directive: !depends juliandate.js
10621  * 
10622  * @constructor
10623  * @extends ilib.Date
10624  * @param {Object=} params parameters that govern the settings and behaviour of this Julian date
10625  */
10626 ilib.Date.JulDate = function(params) {
10627 	this.cal = new ilib.Cal.Julian();
10628 	
10629 	if (params) {
10630 		if (params.locale) {
10631 			this.locale = (typeof(params.locale) === 'string') ? new ilib.Locale(params.locale) : params.locale;
10632 			var li = new ilib.LocaleInfo(this.locale);
10633 			this.timezone = li.getTimeZone(); 
10634 		}
10635 		if (params.timezone) {
10636 			this.timezone = params.timezone;
10637 		}
10638 		
10639 		if (params.year || params.month || params.day || params.hour ||
10640 				params.minute || params.second || params.millisecond ) {
10641 			/**
10642 			 * Year in the Julian calendar.
10643 			 * @type number
10644 			 */
10645 			this.year = parseInt(params.year, 10) || 0;
10646 			/**
10647 			 * The month number, ranging from 1 (January) to 12 (December).
10648 			 * @type number
10649 			 */
10650 			this.month = parseInt(params.month, 10) || 1;
10651 			/**
10652 			 * The day of the month. This ranges from 1 to 31.
10653 			 * @type number
10654 			 */
10655 			this.day = parseInt(params.day, 10) || 1;
10656 			/**
10657 			 * The hour of the day. This can be a number from 0 to 23, as times are
10658 			 * stored unambiguously in the 24-hour clock.
10659 			 * @type number
10660 			 */
10661 			this.hour = parseInt(params.hour, 10) || 0;
10662 			/**
10663 			 * The minute of the hours. Ranges from 0 to 59.
10664 			 * @type number
10665 			 */
10666 			this.minute = parseInt(params.minute, 10) || 0;
10667 			/**
10668 			 * The second of the minute. Ranges from 0 to 59.
10669 			 * @type number
10670 			 */
10671 			this.second = parseInt(params.second, 10) || 0;
10672 			/**
10673 			 * The millisecond of the second. Ranges from 0 to 999.
10674 			 * @type number
10675 			 */
10676 			this.millisecond = parseInt(params.millisecond, 10) || 0;
10677 			
10678 			/**
10679 			 * The day of the year. Ranges from 1 to 383.
10680 			 * @type number
10681 			 */
10682 			this.dayOfYear = parseInt(params.dayOfYear, 10);
10683 			
10684 			if (typeof(params.dst) === 'boolean') {
10685 				this.dst = params.dst;
10686 			}
10687 			
10688 			this.rd = this.newRd(this);
10689 			
10690 			// add the time zone offset to the rd to convert to UTC
10691 			if (!this.tz) {
10692 				this.tz = new ilib.TimeZone({id: this.timezone});
10693 			}
10694 			// getOffsetMillis requires that this.year, this.rd, and this.dst 
10695 			// are set in order to figure out which time zone rules apply and 
10696 			// what the offset is at that point in the year
10697 			this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
10698 			if (this.offset !== 0) {
10699 				this.rd = this.newRd({
10700 					rd: this.rd.getRataDie() - this.offset
10701 				});
10702 			}
10703 		}
10704 	}
10705 	
10706 	if (!this.rd) {
10707 		this.rd = this.newRd(params);
10708 		this._calcDateComponents();
10709 	}
10710 };
10711 
10712 ilib.Date.JulDate.prototype = new ilib.Date({noinstance: true});
10713 ilib.Date.JulDate.prototype.parent = ilib.Date;
10714 ilib.Date.JulDate.prototype.constructor = ilib.Date.JulDate;
10715 
10716 /**
10717  * the cumulative lengths of each month, for a non-leap year 
10718  * @private
10719  * @const
10720  * @type Array.<number>
10721  */
10722 ilib.Date.JulDate.cumMonthLengths = [
10723     0,   /* Jan */
10724 	31,  /* Feb */
10725 	59,  /* Mar */
10726 	90,  /* Apr */
10727 	120, /* May */
10728 	151, /* Jun */
10729 	181, /* Jul */
10730 	212, /* Aug */
10731 	243, /* Sep */
10732 	273, /* Oct */
10733 	304, /* Nov */
10734 	334, /* Dec */
10735 	365
10736 ];
10737 
10738 /**
10739  * the cumulative lengths of each month, for a leap year 
10740  * @private
10741  * @const
10742  * @type Array.<number>
10743  */
10744 ilib.Date.JulDate.cumMonthLengthsLeap = [
10745 	0,   /* Jan */
10746 	31,  /* Feb */
10747 	60,  /* Mar */
10748 	91,  /* Apr */
10749 	121, /* May */
10750 	152, /* Jun */
10751 	182, /* Jul */
10752 	213, /* Aug */
10753 	244, /* Sep */
10754 	274, /* Oct */
10755 	305, /* Nov */
10756 	335, /* Dec */
10757 	366
10758 ];
10759 
10760 /**
10761  * Return a new RD for this date type using the given params.
10762  * @protected
10763  * @param {Object=} params the parameters used to create this rata die instance
10764  * @returns {ilib.Date.RataDie} the new RD instance for the given params
10765  */
10766 ilib.Date.JulDate.prototype.newRd = function (params) {
10767 	return new ilib.Date.JulianRataDie(params);
10768 };
10769 
10770 /**
10771  * Return the year for the given RD
10772  * @protected
10773  * @param {number} rd RD to calculate from 
10774  * @returns {number} the year for the RD
10775  */
10776 ilib.Date.JulDate.prototype._calcYear = function(rd) {
10777 	var year = Math.floor((4*(Math.floor(rd)-1) + 1464)/1461);
10778 	
10779 	return (year <= 0) ? year - 1 : year;
10780 };
10781 
10782 /**
10783  * Calculate date components for the given RD date.
10784  * @protected
10785  */
10786 ilib.Date.JulDate.prototype._calcDateComponents = function () {
10787 	var remainder,
10788 		cumulative,
10789 		rd = this.rd.getRataDie();
10790 	
10791 	this.year = this._calcYear(rd);
10792 
10793 	if (typeof(this.offset) === "undefined") {
10794 		this.year = this._calcYear(rd);
10795 		
10796 		// now offset the RD by the time zone, then recalculate in case we were 
10797 		// near the year boundary
10798 		if (!this.tz) {
10799 			this.tz = new ilib.TimeZone({id: this.timezone});
10800 		}
10801 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
10802 	}
10803 
10804 	if (this.offset !== 0) {
10805 		rd += this.offset;
10806 		this.year = this._calcYear(rd);
10807 	}
10808 	
10809 	var jan1 = this.newRd({
10810 		year: this.year,
10811 		month: 1,
10812 		day: 1,
10813 		hour: 0,
10814 		minute: 0,
10815 		second: 0,
10816 		millisecond: 0
10817 	});
10818 	remainder = rd + 1 - jan1.getRataDie();
10819 	
10820 	cumulative = this.cal.isLeapYear(this.year) ? 
10821 		ilib.Date.JulDate.cumMonthLengthsLeap : 
10822 		ilib.Date.JulDate.cumMonthLengths; 
10823 	
10824 	this.month = ilib.bsearch(Math.floor(remainder), cumulative);
10825 	remainder = remainder - cumulative[this.month-1];
10826 	
10827 	this.day = Math.floor(remainder);
10828 	remainder -= this.day;
10829 	// now convert to milliseconds for the rest of the calculation
10830 	remainder = Math.round(remainder * 86400000);
10831 	
10832 	this.hour = Math.floor(remainder/3600000);
10833 	remainder -= this.hour * 3600000;
10834 	
10835 	this.minute = Math.floor(remainder/60000);
10836 	remainder -= this.minute * 60000;
10837 	
10838 	this.second = Math.floor(remainder/1000);
10839 	remainder -= this.second * 1000;
10840 	
10841 	this.millisecond = remainder;
10842 };
10843 
10844 /**
10845  * Return the day of the week of this date. The day of the week is encoded
10846  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
10847  * 
10848  * @return {number} the day of the week
10849  */
10850 ilib.Date.JulDate.prototype.getDayOfWeek = function() {
10851 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
10852 	return ilib.mod(rd-2, 7);
10853 };
10854 
10855 /**
10856  * Return the name of the calendar that governs this date.
10857  * 
10858  * @return {string} a string giving the name of the calendar
10859  */
10860 ilib.Date.JulDate.prototype.getCalendar = function() {
10861 	return "julian";
10862 };
10863 
10864 //register with the factory method
10865 ilib.Date._constructors["julian"] = ilib.Date.JulDate;
10866 /*
10867  * gregoriandate.js - Represent a date in the Gregorian calendar
10868  * 
10869  * Copyright © 2012-2014, JEDLSoft
10870  *
10871  * Licensed under the Apache License, Version 2.0 (the "License");
10872  * you may not use this file except in compliance with the License.
10873  * You may obtain a copy of the License at
10874  *
10875  *     http://www.apache.org/licenses/LICENSE-2.0
10876  *
10877  * Unless required by applicable law or agreed to in writing, software
10878  * distributed under the License is distributed on an "AS IS" BASIS,
10879  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10880  *
10881  * See the License for the specific language governing permissions and
10882  * limitations under the License.
10883  */
10884 
10885 /* !depends 
10886 date.js 
10887 calendar/gregorian.js 
10888 util/utils.js
10889 util/search.js
10890 util/math.js
10891 localeinfo.js 
10892 julianday.js
10893 calendar/gregratadie.js
10894 timezone.js
10895 */
10896 
10897 /**
10898  * @class
10899  * Construct a new Gregorian date object. The constructor parameters can 
10900  * contain any of the following properties:
10901  * 
10902  * <ul>
10903  * <li><i>unixtime<i> - sets the time of this instance according to the given 
10904  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
10905  * 
10906  * <li><i>julianday</i> - sets the time of this instance according to the given
10907  * Julian Day instance or the Julian Day given as a float
10908  * 
10909  * <li><i>year</i> - any integer, including 0
10910  * 
10911  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
10912  * 
10913  * <li><i>day</i> - 1 to 31
10914  * 
10915  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
10916  * is always done with an unambiguous 24 hour representation
10917  * 
10918  * <li><i>minute</i> - 0 to 59
10919  * 
10920  * <li><i>second</i> - 0 to 59
10921  * 
10922  * <li><i>millisecond</i> - 0 to 999
10923  * 
10924  * <li><i>dst</i> - boolean used to specify whether the given time components are
10925  * intended to be in daylight time or not. This is only used in the overlap
10926  * time when transitioning from DST to standard time, and the time components are 
10927  * ambiguous. Otherwise at all other times of the year, this flag is ignored.
10928  * If you specify the date using unix time (UTC) or a julian day, then the time is
10929  * already unambiguous and this flag does not need to be specified.
10930  * <p>
10931  * For example, in the US, the transition out of daylight savings time 
10932  * in 2014 happens at Nov 2, 2014 2:00am Daylight Time, when the time falls 
10933  * back to Nov 2, 2014 1:00am Standard Time. If you give a date/time components as 
10934  * "Nov 2, 2014 1:30am", then there are two 1:30am times in that day, and you would 
10935  * have to give the standard flag to indicate which of those two you mean. 
10936  * (dst=true means daylight time, dst=false means standard time).   
10937  * 
10938  * <li><i>timezone</i> - the ilib.TimeZone instance or time zone name as a string 
10939  * of this gregorian date. The date/time is kept in the local time. The time zone
10940  * is used later if this date is formatted according to a different time zone and
10941  * the difference has to be calculated, or when the date format has a time zone
10942  * component in it.
10943  * 
10944  * <li><i>locale</i> - locale for this gregorian date. If the time zone is not 
10945  * given, it can be inferred from this locale. For locales that span multiple
10946  * time zones, the one with the largest population is chosen as the one that 
10947  * represents the locale.
10948  * 
10949  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
10950  * </ul>
10951  *
10952  * If the constructor is called with another Gregorian date instance instead of
10953  * a parameter block, the other instance acts as a parameter block and its
10954  * settings are copied into the current instance.<p>
10955  * 
10956  * If the constructor is called with no arguments at all or if none of the 
10957  * properties listed above 
10958  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
10959  * components are 
10960  * filled in with the current date at the time of instantiation. Note that if
10961  * you do not give the time zone when defaulting to the current time and the 
10962  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
10963  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
10964  * Mean Time").<p>
10965  * 
10966  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
10967  * specified in the params, it is assumed that they have the smallest possible
10968  * value in the range for the property (zero or one).<p>
10969  * 
10970  * Depends directive: !depends gregoriandate.js
10971  * 
10972  * @constructor
10973  * @extends ilib.Date
10974  * @param {Object=} params parameters that govern the settings and behaviour of this Gregorian date
10975  */
10976 ilib.Date.GregDate = function(params) {
10977 	this.cal = new ilib.Cal.Gregorian();
10978 	this.timezone = "local";
10979 
10980 	if (params) {
10981 		if (typeof(params.noinstance) === 'boolean' && params.noinstance) {
10982 			// for doing inheritance, so don't need to fill in the data. The inheriting class only wants the methods.
10983 			return;
10984 		}
10985 		if (params.locale) {
10986 			this.locale = (typeof(params.locale) === 'string') ? new ilib.Locale(params.locale) : params.locale;
10987 			var li = new ilib.LocaleInfo(this.locale);
10988 			this.timezone = li.getTimeZone(); 
10989 		}
10990 		if (params.timezone) {
10991 			this.timezone = params.timezone.toString();
10992 		}
10993 		
10994 		if (params.year || params.month || params.day || params.hour ||
10995 				params.minute || params.second || params.millisecond ) {
10996 			this.year = parseInt(params.year, 10) || 0;
10997 			this.month = parseInt(params.month, 10) || 1;
10998 			this.day = parseInt(params.day, 10) || 1;
10999 			this.hour = parseInt(params.hour, 10) || 0;
11000 			this.minute = parseInt(params.minute, 10) || 0;
11001 			this.second = parseInt(params.second, 10) || 0;
11002 			this.millisecond = parseInt(params.millisecond, 10) || 0;
11003 			if (typeof(params.dst) === 'boolean') {
11004 				this.dst = params.dst;
11005 			}
11006 			this.rd = this.newRd(params);
11007 			
11008 			// add the time zone offset to the rd to convert to UTC
11009 			this.offset = 0;
11010 			if (this.timezone === "local" && typeof(params.dst) === 'undefined') {
11011 				// if dst is defined, the intrinsic Date object has no way of specifying which version of a time you mean
11012 				// in the overlap time at the end of DST. Do you mean the daylight 1:30am or the standard 1:30am? In this
11013 				// case, use the ilib calculations below, which can distinguish between the two properly
11014 				var d = new Date(this.year, this.month-1, this.day, this.hour, this.minute, this.second, this.millisecond);
11015 				this.offset = -d.getTimezoneOffset() / 1440;
11016 			} else {
11017 				if (!this.tz) {
11018 					this.tz = new ilib.TimeZone({id: this.timezone});
11019 				}
11020 				// getOffsetMillis requires that this.year, this.rd, and this.dst 
11021 				// are set in order to figure out which time zone rules apply and 
11022 				// what the offset is at that point in the year
11023 				this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
11024 			}
11025 			if (this.offset !== 0) {
11026 				this.rd = this.newRd({
11027 					rd: this.rd.getRataDie() - this.offset
11028 				});
11029 			}
11030 		}
11031 	} 
11032 
11033 	if (!this.rd) {
11034 		this.rd = this.newRd(params);
11035 		this._calcDateComponents();
11036 	}
11037 };
11038 
11039 ilib.Date.GregDate.prototype = new ilib.Date({noinstance: true});
11040 ilib.Date.GregDate.prototype.parent = ilib.Date;
11041 ilib.Date.GregDate.prototype.constructor = ilib.Date.GregDate;
11042 
11043 /**
11044  * Return a new RD for this date type using the given params.
11045  * @private
11046  * @param {Object=} params the parameters used to create this rata die instance
11047  * @returns {ilib.Date.RataDie} the new RD instance for the given params
11048  */
11049 ilib.Date.GregDate.prototype.newRd = function (params) {
11050 	return new ilib.Date.GregRataDie(params);
11051 };
11052 
11053 /**
11054  * Calculates the Gregorian year for a given rd number.
11055  * @private
11056  * @static
11057  */
11058 ilib.Date.GregDate._calcYear = function(rd) {
11059 	var days400,
11060 		days100,
11061 		days4,
11062 		years400,
11063 		years100,
11064 		years4,
11065 		years1,
11066 		year;
11067 
11068 	years400 = Math.floor((rd - 1) / 146097);
11069 	days400 = ilib.mod((rd - 1), 146097);
11070 	years100 = Math.floor(days400 / 36524);
11071 	days100 = ilib.mod(days400, 36524);
11072 	years4 = Math.floor(days100 / 1461);
11073 	days4 = ilib.mod(days100, 1461);
11074 	years1 = Math.floor(days4 / 365);
11075 	
11076 	year = 400 * years400 + 100 * years100 + 4 * years4 + years1;
11077 	if (years100 !== 4 && years1 !== 4) {
11078 		year++;
11079 	}
11080 	return year;
11081 };
11082 
11083 /**
11084  * @private
11085  */
11086 ilib.Date.GregDate.prototype._calcYear = function(rd) {
11087 	return ilib.Date.GregDate._calcYear(rd);
11088 };
11089 
11090 /**
11091  * Calculate the date components for the current time zone
11092  * @private
11093  */
11094 ilib.Date.GregDate.prototype._calcDateComponents = function () {
11095 	if (this.timezone === "local" && this.rd.getRataDie() >= -99280837 && this.rd.getRataDie() <= 100719163) {
11096 		// console.log("using js Date to calculate offset");
11097 		// use the intrinsic JS Date object to do the tz conversion for us, which 
11098 		// guarantees that it follows the system tz database settings 
11099 		var d = new Date(this.rd.getTimeExtended());
11100 	
11101 		/**
11102 		 * Year in the Gregorian calendar.
11103 		 * @type number
11104 		 */
11105 		this.year = d.getFullYear();
11106 		
11107 		/**
11108 		 * The month number, ranging from 1 (January) to 12 (December).
11109 		 * @type number
11110 		 */
11111 		this.month = d.getMonth()+1;
11112 		
11113 		/**
11114 		 * The day of the month. This ranges from 1 to 31.
11115 		 * @type number
11116 		 */
11117 		this.day = d.getDate();
11118 		
11119 		/**
11120 		 * The hour of the day. This can be a number from 0 to 23, as times are
11121 		 * stored unambiguously in the 24-hour clock.
11122 		 * @type number
11123 		 */
11124 		this.hour = d.getHours();
11125 		
11126 		/**
11127 		 * The minute of the hours. Ranges from 0 to 59.
11128 		 * @type number
11129 		 */
11130 		this.minute = d.getMinutes();
11131 		
11132 		/**
11133 		 * The second of the minute. Ranges from 0 to 59.
11134 		 * @type number
11135 		 */
11136 		this.second = d.getSeconds();
11137 		
11138 		/**
11139 		 * The millisecond of the second. Ranges from 0 to 999.
11140 		 * @type number
11141 		 */
11142 		this.millisecond = d.getMilliseconds();
11143 		
11144 		this.offset = -d.getTimezoneOffset() / 1440;
11145 	} else {
11146 		// console.log("using ilib to calculate offset. tz is " + this.timezone);
11147 		// console.log("GregDate._calcDateComponents: date is " + JSON.stringify(this) + " parent is " + JSON.stringify(this.parent) + " and parent.parent is " + JSON.stringify(this.parent.parent));
11148 		if (typeof(this.offset) === "undefined") {
11149 			// console.log("calculating offset");
11150 			this.year = this._calcYear(this.rd.getRataDie());
11151 			
11152 			// now offset the RD by the time zone, then recalculate in case we were 
11153 			// near the year boundary
11154 			if (!this.tz) {
11155 				this.tz = new ilib.TimeZone({id: this.timezone});
11156 			}
11157 			this.offset = this.tz.getOffsetMillis(this) / 86400000;
11158 		// } else {
11159 			// console.log("offset is already defined somehow. type is " + typeof(this.offset));
11160 			// console.trace("Stack is this one");
11161 		}
11162 		// console.log("offset is " + this.offset);
11163 		var rd = this.rd.getRataDie();
11164 		if (this.offset !== 0) {
11165 			rd += this.offset;
11166 		}
11167 		this.year = this._calcYear(rd);
11168 		
11169 		var yearStartRd = this.newRd({
11170 			year: this.year,
11171 			month: 1,
11172 			day: 1,
11173 			cal: this.cal
11174 		});
11175 		
11176 		// remainder is days into the year
11177 		var remainder = rd - yearStartRd.getRataDie() + 1;
11178 		
11179 		var cumulative = ilib.Cal.Gregorian.prototype.isLeapYear.call(this.cal, this.year) ? 
11180 			ilib.Date.GregRataDie.cumMonthLengthsLeap : 
11181 			ilib.Date.GregRataDie.cumMonthLengths; 
11182 		
11183 		this.month = ilib.bsearch(Math.floor(remainder), cumulative);
11184 		remainder = remainder - cumulative[this.month-1];
11185 		
11186 		this.day = Math.floor(remainder);
11187 		remainder -= this.day;
11188 		// now convert to milliseconds for the rest of the calculation
11189 		remainder = Math.round(remainder * 86400000);
11190 		
11191 		this.hour = Math.floor(remainder/3600000);
11192 		remainder -= this.hour * 3600000;
11193 		
11194 		this.minute = Math.floor(remainder/60000);
11195 		remainder -= this.minute * 60000;
11196 		
11197 		this.second = Math.floor(remainder/1000);
11198 		remainder -= this.second * 1000;
11199 		
11200 		this.millisecond = Math.floor(remainder);
11201 	}
11202 };
11203 
11204 /**
11205  * Return the day of the week of this date. The day of the week is encoded
11206  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
11207  * 
11208  * @return {number} the day of the week
11209  */
11210 ilib.Date.GregDate.prototype.getDayOfWeek = function() {
11211 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
11212 	return ilib.mod(rd, 7);
11213 };
11214 
11215 /**
11216  * Return the ordinal day of the year. Days are counted from 1 and proceed linearly up to 
11217  * 365, regardless of months or weeks, etc. That is, January 1st is day 1, and 
11218  * December 31st is 365 in regular years, or 366 in leap years.
11219  * @return {number} the ordinal day of the year
11220  */
11221 ilib.Date.GregDate.prototype.getDayOfYear = function() {
11222 	var cumulativeMap = this.cal.isLeapYear(this.year) ? 
11223 		ilib.Date.GregRataDie.cumMonthLengthsLeap : 
11224 		ilib.Date.GregRataDie.cumMonthLengths; 
11225 		
11226 	return cumulativeMap[this.month-1] + this.day;
11227 };
11228 
11229 /**
11230  * Return the era for this date as a number. The value for the era for Gregorian 
11231  * calendars is -1 for "before the common era" (BCE) and 1 for "the common era" (CE). 
11232  * BCE dates are any date before Jan 1, 1 CE. In the proleptic Gregorian calendar, 
11233  * there is a year 0, so any years that are negative or zero are BCE. In the Julian
11234  * calendar, there is no year 0. Instead, the calendar goes straight from year -1 to 
11235  * 1.
11236  * @return {number} 1 if this date is in the common era, -1 if it is before the 
11237  * common era 
11238  */
11239 ilib.Date.GregDate.prototype.getEra = function() {
11240 	return (this.year < 1) ? -1 : 1;
11241 };
11242 
11243 /**
11244  * Return the name of the calendar that governs this date.
11245  * 
11246  * @return {string} a string giving the name of the calendar
11247  */
11248 ilib.Date.GregDate.prototype.getCalendar = function() {
11249 	return "gregorian";
11250 };
11251 
11252 // register with the factory method
11253 ilib.Date._constructors["gregorian"] = ilib.Date.GregDate;
11254 /*
11255  * thaisolar.js - Represent a Thai solar calendar object.
11256  * 
11257  * Copyright © 2013-2014, JEDLSoft
11258  *
11259  * Licensed under the Apache License, Version 2.0 (the "License");
11260  * you may not use this file except in compliance with the License.
11261  * You may obtain a copy of the License at
11262  *
11263  *     http://www.apache.org/licenses/LICENSE-2.0
11264  *
11265  * Unless required by applicable law or agreed to in writing, software
11266  * distributed under the License is distributed on an "AS IS" BASIS,
11267  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11268  *
11269  * See the License for the specific language governing permissions and
11270  * limitations under the License.
11271  */
11272 
11273 
11274 /* !depends calendar.js locale.js date.js julianday.js calendar/gregorian.js util/utils.js util/math.js */
11275 
11276 /**
11277  * @class
11278  * Construct a new Thai solar calendar object. This class encodes information about
11279  * a Thai solar calendar.<p>
11280  * 
11281  * Depends directive: !depends thaisolar.js
11282  * 
11283  * @constructor
11284  * @implements ilib.Cal
11285  */
11286 ilib.Cal.ThaiSolar = function() {
11287 	this.type = "thaisolar";
11288 };
11289 
11290 ilib.Cal.ThaiSolar.prototype = new ilib.Cal.Gregorian();
11291 ilib.Cal.ThaiSolar.prototype.parent = ilib.Cal.Gregorian;
11292 ilib.Cal.ThaiSolar.prototype.constructor = ilib.Cal.ThaiSolar;
11293 
11294 /**
11295  * Return true if the given year is a leap year in the Thai solar calendar.
11296  * The year parameter may be given as a number, or as a ThaiSolarDate object.
11297  * @param {number|ilib.Date.ThaiSolarDate} year the year for which the leap year information is being sought
11298  * @return {boolean} true if the given year is a leap year
11299  */
11300 ilib.Cal.ThaiSolar.prototype.isLeapYear = function(year) {
11301 	var y = (typeof(year) === 'number' ? year : year.getYears());
11302 	y -= 543;
11303 	var centuries = ilib.mod(y, 400);
11304 	return (ilib.mod(y, 4) === 0 && centuries !== 100 && centuries !== 200 && centuries !== 300);
11305 };
11306 
11307 /**
11308  * Return a date instance for this calendar type using the given
11309  * options.
11310  * @param {Object} options options controlling the construction of 
11311  * the date instance
11312  * @return {ilib.Date} a date appropriate for this calendar type
11313  */
11314 ilib.Cal.ThaiSolar.prototype.newDateInstance = function (options) {
11315 	return new ilib.Date.ThaiSolarDate(options);
11316 };
11317 
11318 /* register this calendar for the factory method */
11319 ilib.Cal._constructors["thaisolar"] = ilib.Cal.ThaiSolar;
11320 /*
11321  * thaisolardate.js - Represent a date in the ThaiSolar calendar
11322  * 
11323  * Copyright © 2013-2014, JEDLSoft
11324  *
11325  * Licensed under the Apache License, Version 2.0 (the "License");
11326  * you may not use this file except in compliance with the License.
11327  * You may obtain a copy of the License at
11328  *
11329  *     http://www.apache.org/licenses/LICENSE-2.0
11330  *
11331  * Unless required by applicable law or agreed to in writing, software
11332  * distributed under the License is distributed on an "AS IS" BASIS,
11333  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11334  *
11335  * See the License for the specific language governing permissions and
11336  * limitations under the License.
11337  */
11338 
11339 /* !depends 
11340 date.js 
11341 calendar/gregorian.js 
11342 util/jsutils.js
11343 */
11344 
11345 /**
11346  * @class
11347  * Construct a new Thai solar date object. The constructor parameters can 
11348  * contain any of the following properties:
11349  * 
11350  * <ul>
11351  * <li><i>unixtime<i> - sets the time of this instance according to the given 
11352  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
11353  * 
11354  * <li><i>julianday</i> - sets the time of this instance according to the given
11355  * Julian Day instance or the Julian Day given as a float
11356  * 
11357  * <li><i>year</i> - any integer, including 0
11358  * 
11359  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
11360  * 
11361  * <li><i>day</i> - 1 to 31
11362  * 
11363  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
11364  * is always done with an unambiguous 24 hour representation
11365  * 
11366  * <li><i>minute</i> - 0 to 59
11367  * 
11368  * <li><i>second</i> - 0 to 59
11369  * 
11370  * <li><i>millisecond</i> - 0 to 999
11371  * 
11372  * <li><i>timezone</i> - the ilib.TimeZone instance or time zone name as a string 
11373  * of this Thai solar date. The date/time is kept in the local time. The time zone
11374  * is used later if this date is formatted according to a different time zone and
11375  * the difference has to be calculated, or when the date format has a time zone
11376  * component in it.
11377  * 
11378  * <li><i>locale</i> - locale for this Thai solar date. If the time zone is not 
11379  * given, it can be inferred from this locale. For locales that span multiple
11380  * time zones, the one with the largest population is chosen as the one that 
11381  * represents the locale. 
11382  * </ul>
11383  *
11384  * If the constructor is called with another Thai solar date instance instead of
11385  * a parameter block, the other instance acts as a parameter block and its
11386  * settings are copied into the current instance.<p>
11387  * 
11388  * If the constructor is called with no arguments at all or if none of the 
11389  * properties listed above 
11390  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
11391  * components are 
11392  * filled in with the current date at the time of instantiation. Note that if
11393  * you do not give the time zone when defaulting to the current time and the 
11394  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
11395  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
11396  * Mean Time").<p>
11397  * 
11398  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
11399  * specified in the params, it is assumed that they have the smallest possible
11400  * value in the range for the property (zero or one).<p>
11401  * 
11402  * Depends directive: !depends thaisolardate.js
11403  * 
11404  * @constructor
11405  * @extends ilib.Date.GregDate
11406  * @param {Object=} params parameters that govern the settings and behaviour of this Thai solar date
11407  */
11408 ilib.Date.ThaiSolarDate = function(params) {
11409 	var p = params;
11410 	if (params) {
11411 		// there is 198327 days difference between the Thai solar and 
11412 		// Gregorian epochs which is equivalent to 543 years
11413 		p = {};
11414 		ilib.shallowCopy(params, p);
11415 		if (typeof(p.year) !== 'undefined') {
11416 			p.year -= 543;	
11417 		}
11418 		if (typeof(p.rd) !== 'undefined') {
11419 			p.rd -= 198327;
11420 		}
11421 	}
11422 	this.rd = undefined; // clear these out so that the GregDate constructor can set it
11423 	this.offset = undefined;
11424 	//console.log("ThaiSolarDate.constructor: date is " + JSON.stringify(this) + " parent is " + JSON.stringify(this.parent) + " and parent.parent is " + JSON.stringify(this.parent.parent));
11425 	ilib.Date.GregDate.call(this, p);
11426 	this.cal = new ilib.Cal.ThaiSolar();
11427 	// make sure the year is set correctly
11428 	if (params && typeof(params.year) !== 'undefined') {
11429 		this.year = parseInt(params.year, 10);
11430 	}
11431 };
11432 
11433 ilib.Date.ThaiSolarDate.prototype = new ilib.Date.GregDate({noinstance: true});
11434 ilib.Date.ThaiSolarDate.prototype.parent = ilib.Date.GregDate.prototype;
11435 ilib.Date.ThaiSolarDate.prototype.constructor = ilib.Date.ThaiSolarDate;
11436 
11437 /**
11438  * the difference between a zero Julian day and the zero Thai Solar date.
11439  * This is some 543 years before the start of the Gregorian epoch. 
11440  * @private
11441  * @const
11442  * @type number
11443  */
11444 ilib.Date.ThaiSolarDate.epoch = 1523097.5;
11445 
11446 /**
11447  * Calculate the date components for the current time zone
11448  * @protected
11449  */
11450 ilib.Date.ThaiSolarDate.prototype._calcDateComponents = function () {
11451 	// there is 198327 days difference between the Thai solar and 
11452 	// Gregorian epochs which is equivalent to 543 years
11453 	// console.log("ThaiSolarDate._calcDateComponents: date is " + JSON.stringify(this) + " parent is " + JSON.stringify(this.parent) + " and parent.parent is " + JSON.stringify(this.parent.parent));
11454 	this.parent._calcDateComponents.call(this);
11455 	this.year += 543;
11456 };
11457 
11458 /**
11459  * Return the Rata Die (fixed day) number of this date.
11460  * 
11461  * @protected
11462  * @return {number} the rd date as a number
11463  */
11464 ilib.Date.ThaiSolarDate.prototype.getRataDie = function() {
11465 	// there is 198327 days difference between the Thai solar and 
11466 	// Gregorian epochs which is equivalent to 543 years
11467 	return this.rd.getRataDie() + 198327;
11468 };
11469 
11470 /**
11471  * Return a new Gregorian date instance that represents the first instance of the 
11472  * given day of the week before the current date. The day of the week is encoded
11473  * as a number where 0 = Sunday, 1 = Monday, etc.
11474  * 
11475  * @param {number} dow the day of the week before the current date that is being sought
11476  * @return {ilib.Date} the date being sought
11477  */
11478 ilib.Date.ThaiSolarDate.prototype.before = function (dow) {
11479 	return this.cal.newDateInstance({
11480 		rd: this.rd.before(dow, this.offset) + 198327,
11481 		timezone: this.timezone
11482 	});
11483 };
11484 
11485 /**
11486  * Return a new Gregorian date instance that represents the first instance of the 
11487  * given day of the week after the current date. The day of the week is encoded
11488  * as a number where 0 = Sunday, 1 = Monday, etc.
11489  * 
11490  * @param {number} dow the day of the week after the current date that is being sought
11491  * @return {ilib.Date} the date being sought
11492  */
11493 ilib.Date.ThaiSolarDate.prototype.after = function (dow) {
11494 	return this.cal.newDateInstance({
11495 		rd: this.rd.after(dow, this.offset) + 198327,
11496 		timezone: this.timezone
11497 	});
11498 };
11499 
11500 /**
11501  * Return a new Gregorian date instance that represents the first instance of the 
11502  * given day of the week on or before the current date. The day of the week is encoded
11503  * as a number where 0 = Sunday, 1 = Monday, etc.
11504  * 
11505  * @param {number} dow the day of the week on or before the current date that is being sought
11506  * @return {ilib.Date} the date being sought
11507  */
11508 ilib.Date.ThaiSolarDate.prototype.onOrBefore = function (dow) {
11509 	return this.cal.newDateInstance({
11510 		rd: this.rd.onOrBefore(dow, this.offset) + 198327,
11511 		timezone: this.timezone
11512 	});
11513 };
11514 
11515 /**
11516  * Return a new Gregorian date instance that represents the first instance of the 
11517  * given day of the week on or after the current date. The day of the week is encoded
11518  * as a number where 0 = Sunday, 1 = Monday, etc.
11519  * 
11520  * @param {number} dow the day of the week on or after the current date that is being sought
11521  * @return {ilib.Date} the date being sought
11522  */
11523 ilib.Date.ThaiSolarDate.prototype.onOrAfter = function (dow) {
11524 	return this.cal.newDateInstance({
11525 		rd: this.rd.onOrAfter(dow, this.offset) + 198327,
11526 		timezone: this.timezone
11527 	});
11528 };
11529 
11530 /**
11531  * Return the name of the calendar that governs this date.
11532  * 
11533  * @return {string} a string giving the name of the calendar
11534  */
11535 ilib.Date.ThaiSolarDate.prototype.getCalendar = function() {
11536 	return "thaisolar";
11537 };
11538 
11539 //register with the factory method
11540 ilib.Date._constructors["thaisolar"] = ilib.Date.ThaiSolarDate;
11541 
11542 
11543 /*
11544  * persian.js - Represent a Persian algorithmic calendar object.
11545  * 
11546  * Copyright © 2014, 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 
11563 /* !depends calendar.js locale.js date.js julianday.js util/utils.js util/math.js */
11564 
11565 /**
11566  * @class
11567  * Construct a new Persian algorithmic calendar object. This class encodes information about
11568  * a Persian algorithmic calendar.<p>
11569  * 
11570  * Depends directive: !depends persian.js
11571  * 
11572  * @constructor
11573  * @implements ilib.Cal
11574  */
11575 ilib.Cal.PersianAlgo = function() {
11576 	this.type = "persian-algo";
11577 };
11578 
11579 /**
11580  * @private
11581  * @const
11582  * @type Array.<number> 
11583  * the lengths of each month 
11584  */
11585 ilib.Cal.PersianAlgo.monthLengths = [
11586 	31,  // Farvardin
11587 	31,  // Ordibehesht
11588 	31,  // Khordad
11589 	31,  // Tir
11590 	31,  // Mordad
11591 	31,  // Shahrivar
11592 	30,  // Mehr
11593 	30,  // Aban
11594 	30,  // Azar
11595 	30,  // Dey
11596 	30,  // Bahman
11597 	29   // Esfand
11598 ];
11599 
11600 /**
11601  * Return the number of months in the given year. The number of months in a year varies
11602  * for some luni-solar calendars because in some years, an extra month is needed to extend the 
11603  * days in a year to an entire solar year. The month is represented as a 1-based number
11604  * where 1=first month, 2=second month, etc.
11605  * 
11606  * @param {number} year a year for which the number of months is sought
11607  * @return {number} The number of months in the given year
11608  */
11609 ilib.Cal.PersianAlgo.prototype.getNumMonths = function(year) {
11610 	return 12;
11611 };
11612 
11613 /**
11614  * Return the number of days in a particular month in a particular year. This function
11615  * can return a different number for a month depending on the year because of things
11616  * like leap years.
11617  * 
11618  * @param {number} month the month for which the length is sought
11619  * @param {number} year the year within which that month can be found
11620  * @return {number} the number of days within the given month in the given year
11621  */
11622 ilib.Cal.PersianAlgo.prototype.getMonLength = function(month, year) {
11623 	if (month !== 12 || !this.isLeapYear(year)) {
11624 		return ilib.Cal.PersianAlgo.monthLengths[month-1];
11625 	} else {
11626 		// Month 12, Esfand, has 30 days instead of 29 in leap years
11627 		return 30;
11628 	}
11629 };
11630 
11631 /**
11632  * Return the equivalent year in the 2820 year cycle that begins on 
11633  * Far 1, 474. This particular cycle obeys the cycle-of-years formula 
11634  * whereas the others do not specifically. This cycle can be used as
11635  * a proxy for other years outside of the cycle by shifting them into 
11636  * the cycle.   
11637  * @param {number} year year to find the equivalent cycle year for
11638  * @returns {number} the equivalent cycle year
11639  */
11640 ilib.Cal.PersianAlgo.prototype.equivalentCycleYear = function(year) {
11641 	var y = year - (year >= 0 ? 474 : 473);
11642 	return ilib.mod(y, 2820) + 474;
11643 };
11644 
11645 /**
11646  * Return true if the given year is a leap year in the Persian calendar.
11647  * The year parameter may be given as a number, or as a PersAlgoDate object.
11648  * @param {number} year the year for which the leap year information is being sought
11649  * @return {boolean} true if the given year is a leap year
11650  */
11651 ilib.Cal.PersianAlgo.prototype.isLeapYear = function(year) {
11652 	return (ilib.mod((this.equivalentCycleYear(year) + 38) * 682, 2816) < 682);
11653 };
11654 
11655 /**
11656  * Return the type of this calendar.
11657  * 
11658  * @return {string} the name of the type of this calendar 
11659  */
11660 ilib.Cal.PersianAlgo.prototype.getType = function() {
11661 	return this.type;
11662 };
11663 
11664 /**
11665  * Return a date instance for this calendar type using the given
11666  * options.
11667  * @param {Object} options options controlling the construction of 
11668  * the date instance
11669  * @return {ilib.Date} a date appropriate for this calendar type
11670  */
11671 ilib.Cal.PersianAlgo.prototype.newDateInstance = function (options) {
11672 	return new ilib.Date.PersAlgoDate(options);
11673 };
11674 
11675 /* register this calendar for the factory method */
11676 ilib.Cal._constructors["persian-algo"] = ilib.Cal.PersianAlgo;
11677 
11678 /*
11679  * persiandate.js - Represent a date in the Persian algorithmic calendar
11680  * 
11681  * Copyright © 2014, JEDLSoft
11682  *
11683  * Licensed under the Apache License, Version 2.0 (the "License");
11684  * you may not use this file except in compliance with the License.
11685  * You may obtain a copy of the License at
11686  *
11687  *     http://www.apache.org/licenses/LICENSE-2.0
11688  *
11689  * Unless required by applicable law or agreed to in writing, software
11690  * distributed under the License is distributed on an "AS IS" BASIS,
11691  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11692  *
11693  * See the License for the specific language governing permissions and
11694  * limitations under the License.
11695  */
11696 
11697 /* !depends 
11698 date.js 
11699 calendar/persian.js 
11700 util/utils.js
11701 util/search.js
11702 util/math.js
11703 localeinfo.js 
11704 julianday.js 
11705 */
11706 
11707 /**
11708  * Construct a new Persian RD date number object. The constructor parameters can 
11709  * contain any of the following properties:
11710  * 
11711  * <ul>
11712  * <li><i>unixtime<i> - sets the time of this instance according to the given 
11713  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970, Gregorian
11714  * 
11715  * <li><i>julianday</i> - sets the time of this instance according to the given
11716  * Julian Day instance or the Julian Day given as a float
11717  * 
11718  * <li><i>year</i> - any integer, including 0
11719  * 
11720  * <li><i>month</i> - 1 to 12, where 1 means Farvardin, 2 means Ordibehesht, etc.
11721  * 
11722  * <li><i>day</i> - 1 to 31
11723  * 
11724  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
11725  * is always done with an unambiguous 24 hour representation
11726  * 
11727  * <li><i>minute</i> - 0 to 59
11728  * 
11729  * <li><i>second</i> - 0 to 59
11730  * 
11731  * <li><i>millisecond</i> - 0 to 999
11732  * 
11733  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
11734  * </ul>
11735  *
11736  * If the constructor is called with another Persian date instance instead of
11737  * a parameter block, the other instance acts as a parameter block and its
11738  * settings are copied into the current instance.<p>
11739  * 
11740  * If the constructor is called with no arguments at all or if none of the 
11741  * properties listed above are present, then the RD is calculate based on 
11742  * the current date at the time of instantiation. <p>
11743  * 
11744  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
11745  * specified in the params, it is assumed that they have the smallest possible
11746  * value in the range for the property (zero or one).<p>
11747  * 
11748  * Depends directive: !depends persiandate.js
11749  * 
11750  * @private
11751  * @class
11752  * @constructor
11753  * @extends ilib.Date.RataDie
11754  * @param {Object=} params parameters that govern the settings and behaviour of this Persian RD date
11755  */
11756 ilib.Date.PersAlgoRataDie = function(params) {
11757 	this.cal = params && params.cal || new ilib.Cal.PersianAlgo();
11758 	this.rd = undefined;
11759 	ilib.Date.RataDie.call(this, params);
11760 };
11761 
11762 ilib.Date.PersAlgoRataDie.prototype = new ilib.Date.RataDie();
11763 ilib.Date.PersAlgoRataDie.prototype.parent = ilib.Date.RataDie;
11764 ilib.Date.PersAlgoRataDie.prototype.constructor = ilib.Date.PersAlgoRataDie;
11765 
11766 /**
11767  * The difference between a zero Julian day and the first Persian date
11768  * @private
11769  * @const
11770  * @type number
11771  */
11772 ilib.Date.PersAlgoRataDie.prototype.epoch = 1948319.5;
11773 
11774 /**
11775  * Calculate the Rata Die (fixed day) number of the given date from the
11776  * date components.
11777  *
11778  * @protected
11779  * @param {Object} date the date components to calculate the RD from
11780  */
11781 ilib.Date.PersAlgoRataDie.prototype._setDateComponents = function(date) {
11782 	var year = this.cal.equivalentCycleYear(date.year);
11783 	var y = date.year - (date.year >= 0 ? 474 : 473);
11784 	var rdOfYears = 1029983 * Math.floor(y/2820) + 365 * (year - 1) + Math.floor((682 * year - 110) / 2816);
11785 	var dayInYear = (date.month > 1 ? ilib.Date.PersAlgoDate.cumMonthLengths[date.month-1] : 0) + date.day;
11786 	var rdtime = (date.hour * 3600000 +
11787 		date.minute * 60000 +
11788 		date.second * 1000 +
11789 		date.millisecond) /
11790 		86400000;
11791 	
11792 	/*
11793 	// console.log("getRataDie: converting " +  JSON.stringify(this));
11794 	console.log("getRataDie: year is " +  year);
11795 	console.log("getRataDie: rd of years is " +  rdOfYears);
11796 	console.log("getRataDie: day in year is " +  dayInYear);
11797 	console.log("getRataDie: rdtime is " +  rdtime);
11798 	console.log("getRataDie: rd is " +  (rdOfYears + dayInYear + rdtime));
11799 	*/
11800 	
11801 	this.rd = rdOfYears + dayInYear + rdtime;
11802 };
11803 
11804 /**
11805  * Return the rd number of the particular day of the week on or before the 
11806  * given rd. eg. The Sunday on or before the given rd.
11807  * @private
11808  * @param {number} rd the rata die date of the reference date
11809  * @param {number} dayOfWeek the day of the week that is being sought relative 
11810  * to the current date
11811  * @return {number} the rd of the day of the week
11812  */
11813 ilib.Date.PersAlgoRataDie.prototype._onOrBefore = function(rd, dayOfWeek) {
11814 	return rd - ilib.mod(Math.floor(rd) - dayOfWeek - 3, 7);
11815 };
11816 
11817 
11818 /**
11819  * @class
11820  * 
11821  * Construct a new Persian date object. The constructor parameters can 
11822  * contain any of the following properties:
11823  * 
11824  * <ul>
11825  * <li><i>unixtime<i> - sets the time of this instance according to the given 
11826  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970, Gregorian
11827  * 
11828  * <li><i>julianday</i> - sets the time of this instance according to the given
11829  * Julian Day instance or the Julian Day given as a float
11830  * 
11831  * <li><i>year</i> - any integer, including 0
11832  * 
11833  * <li><i>month</i> - 1 to 12, where 1 means Farvardin, 2 means Ordibehesht, etc.
11834  * 
11835  * <li><i>day</i> - 1 to 31
11836  * 
11837  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
11838  * is always done with an unambiguous 24 hour representation
11839  * 
11840  * <li><i>minute</i> - 0 to 59
11841  * 
11842  * <li><i>second</i> - 0 to 59
11843  * 
11844  * <li><i>millisecond</i> - 0 to 999
11845  * 
11846  * <li><i>timezone</i> - the ilib.TimeZone instance or time zone name as a string 
11847  * of this persian date. The date/time is kept in the local time. The time zone
11848  * is used later if this date is formatted according to a different time zone and
11849  * the difference has to be calculated, or when the date format has a time zone
11850  * component in it.
11851  * 
11852  * <li><i>locale</i> - locale for this persian date. If the time zone is not 
11853  * given, it can be inferred from this locale. For locales that span multiple
11854  * time zones, the one with the largest population is chosen as the one that 
11855  * represents the locale.
11856  * 
11857  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
11858  * </ul>
11859  *
11860  * If the constructor is called with another Persian date instance instead of
11861  * a parameter block, the other instance acts as a parameter block and its
11862  * settings are copied into the current instance.<p>
11863  * 
11864  * If the constructor is called with no arguments at all or if none of the 
11865  * properties listed above 
11866  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
11867  * components are 
11868  * filled in with the current date at the time of instantiation. Note that if
11869  * you do not give the time zone when defaulting to the current time and the 
11870  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
11871  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
11872  * Mean Time").<p>
11873  * 
11874  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
11875  * specified in the params, it is assumed that they have the smallest possible
11876  * value in the range for the property (zero or one).<p>
11877  * 
11878  * Depends directive: !depends persiandate.js
11879  * 
11880  * @constructor
11881  * @extends ilib.Date
11882  * @param {Object=} params parameters that govern the settings and behaviour of this Persian date
11883  */
11884 ilib.Date.PersAlgoDate = function(params) {
11885 	this.cal = new ilib.Cal.PersianAlgo();
11886 	this.timezone = "local";
11887 	
11888 	if (params) {
11889 		if (params.locale) {
11890 			this.locale = (typeof(params.locale) === 'string') ? new ilib.Locale(params.locale) : params.locale;
11891 			var li = new ilib.LocaleInfo(this.locale);
11892 			this.timezone = li.getTimeZone(); 
11893 		}
11894 		if (params.timezone) {
11895 			this.timezone = params.timezone;
11896 		}
11897 		
11898 		if (params.year || params.month || params.day || params.hour ||
11899 				params.minute || params.second || params.millisecond ) {
11900 			/**
11901 			 * Year in the Persian calendar.
11902 			 * @type number
11903 			 */
11904 			this.year = parseInt(params.year, 10) || 0;
11905 
11906 			/**
11907 			 * The month number, ranging from 1 to 12
11908 			 * @type number
11909 			 */
11910 			this.month = parseInt(params.month, 10) || 1;
11911 
11912 			/**
11913 			 * The day of the month. This ranges from 1 to 31.
11914 			 * @type number
11915 			 */
11916 			this.day = parseInt(params.day, 10) || 1;
11917 			
11918 			/**
11919 			 * The hour of the day. This can be a number from 0 to 23, as times are
11920 			 * stored unambiguously in the 24-hour clock.
11921 			 * @type number
11922 			 */
11923 			this.hour = parseInt(params.hour, 10) || 0;
11924 
11925 			/**
11926 			 * The minute of the hours. Ranges from 0 to 59.
11927 			 * @type number
11928 			 */
11929 			this.minute = parseInt(params.minute, 10) || 0;
11930 
11931 			/**
11932 			 * The second of the minute. Ranges from 0 to 59.
11933 			 * @type number
11934 			 */
11935 			this.second = parseInt(params.second, 10) || 0;
11936 
11937 			/**
11938 			 * The millisecond of the second. Ranges from 0 to 999.
11939 			 * @type number
11940 			 */
11941 			this.millisecond = parseInt(params.millisecond, 10) || 0;
11942 			
11943 			/**
11944 			 * The day of the year. Ranges from 1 to 366.
11945 			 * @type number
11946 			 */
11947 			this.dayOfYear = parseInt(params.dayOfYear, 10);
11948 
11949 			if (typeof(params.dst) === 'boolean') {
11950 				this.dst = params.dst;
11951 			}
11952 			
11953 			this.rd = this.newRd(this);
11954 			
11955 			// add the time zone offset to the rd to convert to UTC
11956 			if (!this.tz) {
11957 				this.tz = new ilib.TimeZone({id: this.timezone});
11958 			}
11959 			// getOffsetMillis requires that this.year, this.rd, and this.dst 
11960 			// are set in order to figure out which time zone rules apply and 
11961 			// what the offset is at that point in the year
11962 			this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
11963 			if (this.offset !== 0) {
11964 				this.rd = this.newRd({
11965 					rd: this.rd.getRataDie() - this.offset
11966 				});
11967 			}
11968 		}
11969 	}
11970 
11971 	if (!this.rd) {
11972 		this.rd = this.newRd(params);
11973 		this._calcDateComponents();
11974 	}
11975 };
11976 
11977 ilib.Date.PersAlgoDate.prototype = new ilib.Date({noinstance: true});
11978 ilib.Date.PersAlgoDate.prototype.parent = ilib.Date;
11979 ilib.Date.PersAlgoDate.prototype.constructor = ilib.Date.PersAlgoDate;
11980 
11981 /**
11982  * @private
11983  * @const
11984  * @type Array.<number>
11985  * the cumulative lengths of each month, for a non-leap year 
11986  */
11987 ilib.Date.PersAlgoDate.cumMonthLengths = [
11988     0,    // Farvardin
11989 	31,   // Ordibehesht
11990 	62,   // Khordad
11991 	93,   // Tir
11992 	124,  // Mordad
11993 	155,  // Shahrivar
11994 	186,  // Mehr
11995 	216,  // Aban
11996 	246,  // Azar
11997 	276,  // Dey
11998 	306,  // Bahman
11999 	336,  // Esfand
12000 	365
12001 ];
12002 
12003 /**
12004  * Return a new RD for this date type using the given params.
12005  * @protected
12006  * @param {Object=} params the parameters used to create this rata die instance
12007  * @returns {ilib.Date.RataDie} the new RD instance for the given params
12008  */
12009 ilib.Date.PersAlgoDate.prototype.newRd = function (params) {
12010 	return new ilib.Date.PersAlgoRataDie(params);
12011 };
12012 
12013 /**
12014  * Return the year for the given RD
12015  * @protected
12016  * @param {number} rd RD to calculate from 
12017  * @returns {number} the year for the RD
12018  */
12019 ilib.Date.PersAlgoDate.prototype._calcYear = function(rd) {
12020 	var shiftedRd = rd - 173126;
12021 	var numberOfCycles = Math.floor(shiftedRd / 1029983);
12022 	var shiftedDayInCycle = ilib.mod(shiftedRd, 1029983);
12023 	var yearInCycle = (shiftedDayInCycle === 1029982) ? 2820 : Math.floor((2816 * shiftedDayInCycle + 1031337) / 1028522);
12024 	var year = 474 + 2820 * numberOfCycles + yearInCycle;
12025 	return (year > 0) ? year : year - 1;
12026 };
12027 
12028 /**
12029  * @private
12030  * Calculate date components for the given RD date.
12031  */
12032 ilib.Date.PersAlgoDate.prototype._calcDateComponents = function () {
12033 	var remainder,
12034 		rd = this.rd.getRataDie();
12035 	
12036 	this.year = this._calcYear(rd);
12037 	
12038 	if (typeof(this.offset) === "undefined") {
12039 		// now offset the RD by the time zone, then recalculate in case we were 
12040 		// near the year boundary
12041 		if (!this.tz) {
12042 			this.tz = new ilib.TimeZone({id: this.timezone});
12043 		}
12044 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
12045 	}
12046 	
12047 	if (this.offset !== 0) {
12048 		rd += this.offset;
12049 		this.year = this._calcYear(rd);
12050 	}
12051 	
12052 	//console.log("PersAlgoDate.calcComponent: calculating for rd " + rd);
12053 	//console.log("PersAlgoDate.calcComponent: year is " + ret.year);
12054 	var yearStart = this.newRd({
12055 		year: this.year,
12056 		month: 1,
12057 		day: 1,
12058 		hour: 0,
12059 		minute: 0,
12060 		second: 0,
12061 		millisecond: 0
12062 	});
12063 	remainder = rd - yearStart.getRataDie() + 1;
12064 	
12065 	this.dayOfYear = remainder;
12066 	
12067 	//console.log("PersAlgoDate.calcComponent: remainder is " + remainder);
12068 	
12069 	this.month = ilib.bsearch(remainder, ilib.Date.PersAlgoDate.cumMonthLengths);
12070 	remainder -= ilib.Date.PersAlgoDate.cumMonthLengths[this.month-1];
12071 	
12072 	//console.log("PersAlgoDate.calcComponent: month is " + this.month + " and remainder is " + remainder);
12073 	
12074 	this.day = Math.floor(remainder);
12075 	remainder -= this.day;
12076 	
12077 	//console.log("PersAlgoDate.calcComponent: day is " + this.day + " and remainder is " + remainder);
12078 	
12079 	// now convert to milliseconds for the rest of the calculation
12080 	remainder = Math.round(remainder * 86400000);
12081 	
12082 	this.hour = Math.floor(remainder/3600000);
12083 	remainder -= this.hour * 3600000;
12084 	
12085 	this.minute = Math.floor(remainder/60000);
12086 	remainder -= this.minute * 60000;
12087 	
12088 	this.second = Math.floor(remainder/1000);
12089 	remainder -= this.second * 1000;
12090 	
12091 	this.millisecond = remainder;
12092 };
12093 
12094 /**
12095  * Return the day of the week of this date. The day of the week is encoded
12096  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
12097  * 
12098  * @return {number} the day of the week
12099  */
12100 ilib.Date.PersAlgoDate.prototype.getDayOfWeek = function() {
12101 	var rd = Math.floor(this.getRataDie());
12102 	return ilib.mod(rd-3, 7);
12103 };
12104 
12105 /**
12106  * Return the ordinal day of the year. Days are counted from 1 and proceed linearly up to 
12107  * 365, regardless of months or weeks, etc. That is, Farvardin 1st is day 1, and 
12108  * December 31st is 365 in regular years, or 366 in leap years.
12109  * @return {number} the ordinal day of the year
12110  */
12111 ilib.Date.PersAlgoDate.prototype.getDayOfYear = function() {
12112 	return ilib.Date.PersAlgoDate.cumMonthLengths[this.month-1] + this.day;
12113 };
12114 
12115 /**
12116  * Return the era for this date as a number. The value for the era for Persian 
12117  * calendars is -1 for "before the persian era" (BP) and 1 for "the persian era" (anno 
12118  * persico or AP). 
12119  * BP dates are any date before Farvardin 1, 1 AP. In the proleptic Persian calendar, 
12120  * there is a year 0, so any years that are negative or zero are BP.
12121  * @return {number} 1 if this date is in the common era, -1 if it is before the 
12122  * common era 
12123  */
12124 ilib.Date.PersAlgoDate.prototype.getEra = function() {
12125 	return (this.year < 1) ? -1 : 1;
12126 };
12127 
12128 /**
12129  * Return the name of the calendar that governs this date.
12130  * 
12131  * @return {string} a string giving the name of the calendar
12132  */
12133 ilib.Date.PersAlgoDate.prototype.getCalendar = function() {
12134 	return "persian-algo";
12135 };
12136 
12137 // register with the factory method
12138 ilib.Date._constructors["persian-algo"] = ilib.Date.PersAlgoDate;
12139 /*
12140  * astro.js - Static functions to support astronomical calculations
12141  * 
12142  * Copyright © 2014, JEDLSoft
12143  *
12144  * Licensed under the Apache License, Version 2.0 (the "License");
12145  * you may not use this file except in compliance with the License.
12146  * You may obtain a copy of the License at
12147  *
12148  *     http://www.apache.org/licenses/LICENSE-2.0
12149  *
12150  * Unless required by applicable law or agreed to in writing, software
12151  * distributed under the License is distributed on an "AS IS" BASIS,
12152  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12153  *
12154  * See the License for the specific language governing permissions and
12155  * limitations under the License.
12156  */
12157 
12158 /* !depends
12159 ilibglobal.js
12160 date.js
12161 calendar/gregoriandate.js
12162 calendar/gregratadie.js
12163 */
12164 
12165 // !data astro
12166 
12167 /*
12168  * These routines were derived from a public domain set of JavaScript 
12169  * functions for positional astronomy by John Walker of Fourmilab, 
12170  * September 1999.
12171  */
12172 
12173 /**
12174  * Load in all the data needed for astrological calculations.
12175  * 
12176  * @param {boolean} sync
12177  * @param {*} loadParams
12178  * @param {function(*)|undefined} callback
12179  */
12180 ilib.Date.initAstro = function(sync, loadParams, callback) {
12181 	if (!ilib.data.astro) {
12182 		ilib.loadData({
12183 			name: "astro.json", // countries in their own language 
12184 			locale: "-", // only need to load the root file 
12185 			nonLocale: true,
12186 			sync: sync, 
12187 			loadParams: loadParams, 
12188 			callback: ilib.bind(this, /** @type function() */ function(astroData) {
12189 				/** 
12190 				 * @type {{
12191 				 *  	_EquinoxpTerms:Array.<number>, 
12192 				 *  	_JDE0tab1000:Array.<number>, 
12193 				 *  	_JDE0tab2000:Array.<number>, 
12194 				 *  	_deltaTtab:Array.<number>,
12195 				 *  	_oterms:Array.<number>,
12196 				 *  	_nutArgMult:Array.<number>, 
12197 				 *  	_nutArgCoeff:Array.<number>, 
12198 				 *  	_nutCoeffA:Array.<number>,
12199 				 *  	_nutCoeffB:Array.<number>,
12200 				 *  	_coeff19th:Array.<number>,
12201 				 *  	_coeff18th:Array.<number>,
12202 				 *  	_solarLongCoeff:Array.<number>, 
12203 				 *  	_solarLongMultipliers:Array.<number>, 
12204 				 *  	_solarLongAddends:Array.<number>, 
12205 				 *  	_meanMoonCoeff:Array.<number>,
12206 				 *  	_elongationCoeff:Array.<number>,
12207 				 *  	_solarAnomalyCoeff:Array.<number>,
12208 				 *  	_lunarAnomalyCoeff:Array.<number>,
12209 				 *  	_moonFromNodeCoeff:Array.<number>,
12210 				 *  	_eCoeff:Array.<number>,
12211 				 *  	_lunarElongationLongCoeff:Array.<number>,
12212 				 *  	_solarAnomalyLongCoeff:Array.<number>,
12213 				 *  	_lunarAnomalyLongCoeff:Array.<number>,
12214 				 *  	_moonFromNodeLongCoeff:Array.<number>,
12215 				 *  	_sineCoeff:Array.<number>,
12216 				 *  	_nmApproxCoeff:Array.<number>,
12217 				 *  	_nmCapECoeff:Array.<number>,
12218 				 *  	_nmSolarAnomalyCoeff:Array.<number>,
12219 				 *  	_nmLunarAnomalyCoeff:Array.<number>,
12220 				 *  	_nmMoonArgumentCoeff:Array.<number>,
12221 				 *  	_nmCapOmegaCoeff:Array.<number>,
12222 				 *  	_nmEFactor:Array.<number>,
12223 				 *  	_nmSolarCoeff:Array.<number>,
12224 				 *  	_nmLunarCoeff:Array.<number>,
12225 				 *  	_nmMoonCoeff:Array.<number>,
12226 				 *  	_nmSineCoeff:Array.<number>,
12227 				 *  	_nmAddConst:Array.<number>,
12228 				 *  	_nmAddCoeff:Array.<number>,
12229 				 *  	_nmAddFactor:Array.<number>,
12230 				 *  	_nmExtra:Array.<number>
12231 				 *  }}
12232 				 */ 	
12233 			 	ilib.data.astro = astroData;
12234 				if (callback && typeof(callback) === 'function') {
12235 					callback(astroData);
12236 				}
12237 			})
12238 		});
12239 	} else {
12240 		if (callback && typeof(callback) === 'function') {
12241 			callback(ilib.data.astro);
12242 		}
12243 	}
12244 };
12245 
12246 /**
12247  * Convert degrees to radians.
12248  * 
12249  * @static
12250  * @param {number} d angle in degrees
12251  * @return {number} angle in radians 
12252  */
12253 ilib.Date._dtr = function(d) {
12254 	return (d * Math.PI) / 180.0;
12255 };
12256 
12257 /**
12258  * Convert radians to degrees.
12259  * 
12260  * @static
12261  * @param {number} r angle in radians
12262  * @return {number} angle in degrees 
12263  */
12264 ilib.Date._rtd = function(r) {
12265 	return (r * 180.0) / Math.PI;
12266 };
12267 
12268 /**
12269  * Return the cosine of an angle given in degrees.
12270  * @static
12271  * @param {number} d angle in degrees
12272  * @return {number} cosine of the angle.
12273  */  
12274 ilib.Date._dcos = function(d) {
12275 	return Math.cos(ilib.Date._dtr(d));
12276 };
12277 
12278 /**
12279  * Return the sine of an angle given in degrees.
12280  * @static
12281  * @param {number} d angle in degrees
12282  * @return {number} sine of the angle.
12283  */  
12284 ilib.Date._dsin = function(d) {
12285 	return Math.sin(ilib.Date._dtr(d));
12286 };
12287 
12288 /**
12289  * Return the tan of an angle given in degrees.
12290  * @static
12291  * @param {number} d angle in degrees
12292  * @return {number} tan of the angle.
12293  */  
12294 ilib.Date._dtan = function(d) {
12295 	return Math.tan(ilib.Date._dtr(d));
12296 };
12297 
12298 /**
12299  * Range reduce angle in degrees.
12300  * 
12301  * @static
12302  * @param {number} a angle to reduce
12303  * @return {number} the reduced angle  
12304  */
12305 ilib.Date._fixangle = function(a) {
12306 	return a - 360.0 * (Math.floor(a / 360.0));
12307 };
12308 
12309 /**
12310  * Range reduce angle in radians.
12311  * 
12312  * @static
12313  * @param {number} a angle to reduce
12314  * @return {number} the reduced angle  
12315  */
12316 ilib.Date._fixangr = function(a) {
12317 	return a - (2 * Math.PI) * (Math.floor(a / (2 * Math.PI)));
12318 };
12319 
12320 /**
12321  * Determine the Julian Ephemeris Day of an equinox or solstice.  The "which" 
12322  * argument selects the item to be computed:
12323  * 
12324  * <ul>
12325  * <li>0   March equinox
12326  * <li>1   June solstice
12327  * <li>2   September equinox
12328  * <li>3   December solstice
12329  * </ul>
12330  * 
12331  * @static
12332  * @param {number} year Gregorian year to calculate for
12333  * @param {number} which Which equinox or solstice to calculate
12334  */
12335 ilib.Date._equinox = function(year, which) {
12336 	var deltaL, i, j, JDE0, JDE, JDE0tab, S, T, W, Y;
12337 
12338 	/*  Initialize terms for mean equinox and solstices.  We
12339 	    have two sets: one for years prior to 1000 and a second
12340 	    for subsequent years.  */
12341 
12342 	if (year < 1000) {
12343 		JDE0tab = ilib.data.astro._JDE0tab1000;
12344 		Y = year / 1000;
12345 	} else {
12346 		JDE0tab = ilib.data.astro._JDE0tab2000;
12347 		Y = (year - 2000) / 1000;
12348 	}
12349 
12350 	JDE0 = JDE0tab[which][0] + (JDE0tab[which][1] * Y)
12351 			+ (JDE0tab[which][2] * Y * Y) + (JDE0tab[which][3] * Y * Y * Y)
12352 			+ (JDE0tab[which][4] * Y * Y * Y * Y);
12353 
12354 	//document.debug.log.value += "JDE0 = " + JDE0 + "\n";
12355 
12356 	T = (JDE0 - 2451545.0) / 36525;
12357 	//document.debug.log.value += "T = " + T + "\n";
12358 	W = (35999.373 * T) - 2.47;
12359 	//document.debug.log.value += "W = " + W + "\n";
12360 	deltaL = 1 + (0.0334 * ilib.Date._dcos(W)) + (0.0007 * ilib.Date._dcos(2 * W));
12361 	//document.debug.log.value += "deltaL = " + deltaL + "\n";
12362 
12363 	//  Sum the periodic terms for time T
12364 
12365 	S = 0;
12366 	j = 0;
12367 	for (i = 0; i < 24; i++) {
12368 		S += ilib.data.astro._EquinoxpTerms[j]
12369 				* ilib.Date._dcos(ilib.data.astro._EquinoxpTerms[j + 1] + (ilib.data.astro._EquinoxpTerms[j + 2] * T));
12370 		j += 3;
12371 	}
12372 
12373 	//document.debug.log.value += "S = " + S + "\n";
12374 	//document.debug.log.value += "Corr = " + ((S * 0.00001) / deltaL) + "\n";
12375 
12376 	JDE = JDE0 + ((S * 0.00001) / deltaL);
12377 
12378 	return JDE;
12379 };
12380 
12381 /* 
12382  * The table of observed Delta T values at the beginning of
12383  * years from 1620 through 2014 as found in astro.json is taken from
12384  * http://www.staff.science.uu.nl/~gent0113/deltat/deltat.htm
12385  * and
12386  * ftp://maia.usno.navy.mil/ser7/deltat.data
12387  */
12388 
12389 /**  
12390  * Determine the difference, in seconds, between dynamical time and universal time.
12391  * 
12392  * @static
12393  * @param {number} year to calculate the difference for
12394  * @return {number} difference in seconds between dynamical time and universal time  
12395  */
12396 ilib.Date._deltat = function (year) {
12397 	var dt, f, i, t;
12398 
12399 	if ((year >= 1620) && (year <= 2014)) {
12400 		i = Math.floor(year - 1620);
12401 		f = (year - 1620) - i; /* Fractional part of year */
12402 		dt = ilib.data.astro._deltaTtab[i] + ((ilib.data.astro._deltaTtab[i + 1] - ilib.data.astro._deltaTtab[i]) * f);
12403 	} else {
12404 		t = (year - 2000) / 100;
12405 		if (year < 948) {
12406 			dt = 2177 + (497 * t) + (44.1 * t * t);
12407 		} else {
12408 			dt = 102 + (102 * t) + (25.3 * t * t);
12409 			if ((year > 2000) && (year < 2100)) {
12410 				dt += 0.37 * (year - 2100);
12411 			}
12412 		}
12413 	}
12414 	return dt;
12415 };
12416 
12417 /**
12418  * Calculate the obliquity of the ecliptic for a given
12419  * Julian date.  This uses Laskar's tenth-degree
12420  * polynomial fit (J. Laskar, Astronomy and
12421  * Astrophysics, Vol. 157, page 68 [1986]) which is
12422  * accurate to within 0.01 arc second between AD 1000
12423  * and AD 3000, and within a few seconds of arc for
12424  * +/-10000 years around AD 2000.  If we're outside the
12425  * range in which this fit is valid (deep time) we
12426  * simply return the J2000 value of the obliquity, which
12427  * happens to be almost precisely the mean.
12428  * 
12429  * @static
12430  * @param {number} jd Julian Day to calculate the obliquity for
12431  * @return {number} the obliquity
12432  */
12433 ilib.Date._obliqeq = function (jd) {
12434 	var eps, u, v, i;
12435 
12436  	v = u = (jd - 2451545.0) / 3652500.0;
12437 
12438  	eps = 23 + (26 / 60.0) + (21.448 / 3600.0);
12439 
12440  	if (Math.abs(u) < 1.0) {
12441  		for (i = 0; i < 10; i++) {
12442  			eps += (ilib.data.astro._oterms[i] / 3600.0) * v;
12443  			v *= u;
12444  		}
12445  	}
12446  	return eps;
12447 };
12448 
12449 /**
12450  * Return the position of the sun.  We return
12451  * intermediate values because they are useful in a
12452  * variety of other contexts.
12453  * @static
12454  * @param {number} jd find the position of sun on this Julian Day
12455  * @return {Object} the position of the sun and many intermediate
12456  * values
12457  */
12458 ilib.Date._sunpos = function(jd) {
12459 	var ret = {}, 
12460 		T, T2, T3, Omega, epsilon, epsilon0;
12461 
12462 	T = (jd - 2451545.0) / 36525.0;
12463 	//document.debug.log.value += "Sunpos.  T = " + T + "\n";
12464 	T2 = T * T;
12465 	T3 = T * T2;
12466 	ret.meanLongitude = ilib.Date._fixangle(280.46646 + 36000.76983 * T + 0.0003032 * T2);
12467 	//document.debug.log.value += "ret.meanLongitude = " + ret.meanLongitude + "\n";
12468 	ret.meanAnomaly = ilib.Date._fixangle(357.52911 + (35999.05029 * T) - 0.0001537 * T2 - 0.00000048 * T3);
12469 	//document.debug.log.value += "ret.meanAnomaly = " + ret.meanAnomaly + "\n";
12470 	ret.eccentricity = 0.016708634 - 0.000042037 * T - 0.0000001267 * T2;
12471 	//document.debug.log.value += "e = " + e + "\n";
12472 	ret.equationOfCenter = ((1.914602 - 0.004817 * T - 0.000014 * T2) * ilib.Date._dsin(ret.meanAnomaly))
12473 			+ ((0.019993 - 0.000101 * T) * ilib.Date._dsin(2 * ret.meanAnomaly))
12474 			+ (0.000289 * ilib.Date._dsin(3 * ret.meanAnomaly));
12475 	//document.debug.log.value += "ret.equationOfCenter = " + ret.equationOfCenter + "\n";
12476 	ret.sunLongitude = ret.meanLongitude + ret.equationOfCenter;
12477 	//document.debug.log.value += "ret.sunLongitude = " + ret.sunLongitude + "\n";
12478 	//ret.sunAnomaly = ret.meanAnomaly + ret.equationOfCenter;
12479 	//document.debug.log.value += "ret.sunAnomaly = " + ret.sunAnomaly + "\n";
12480 	// ret.sunRadius = (1.000001018 * (1 - (ret.eccentricity * ret.eccentricity))) / (1 + (ret.eccentricity * ilib.Date._dcos(ret.sunAnomaly)));
12481 	//document.debug.log.value += "ret.sunRadius = " + ret.sunRadius + "\n";
12482 	Omega = 125.04 - (1934.136 * T);
12483 	//document.debug.log.value += "Omega = " + Omega + "\n";
12484 	ret.apparentLong = ret.sunLongitude + (-0.00569) + (-0.00478 * ilib.Date._dsin(Omega));
12485 	//document.debug.log.value += "ret.apparentLong = " + ret.apparentLong + "\n";
12486 	epsilon0 = ilib.Date._obliqeq(jd);
12487 	//document.debug.log.value += "epsilon0 = " + epsilon0 + "\n";
12488 	epsilon = epsilon0 + (0.00256 * ilib.Date._dcos(Omega));
12489 	//document.debug.log.value += "epsilon = " + epsilon + "\n";
12490 	//ret.rightAscension = ilib.Date._fixangle(ilib.Date._rtd(Math.atan2(ilib.Date._dcos(epsilon0) * ilib.Date._dsin(ret.sunLongitude), ilib.Date._dcos(ret.sunLongitude))));
12491 	//document.debug.log.value += "ret.rightAscension = " + ret.rightAscension + "\n";
12492 	// ret.declination = ilib.Date._rtd(Math.asin(ilib.Date._dsin(epsilon0) * ilib.Date._dsin(ret.sunLongitude)));
12493 	////document.debug.log.value += "ret.declination = " + ret.declination + "\n";
12494 	ret.inclination = ilib.Date._fixangle(23.4392911 - 0.013004167 * T - 0.00000016389 * T2 + 0.0000005036 * T3);
12495 	ret.apparentRightAscension = ilib.Date._fixangle(ilib.Date._rtd(Math.atan2(ilib.Date._dcos(epsilon) * ilib.Date._dsin(ret.apparentLong), ilib.Date._dcos(ret.apparentLong))));
12496 	//document.debug.log.value += "ret.apparentRightAscension = " + ret.apparentRightAscension + "\n";
12497 	//ret.apparentDeclination = ilib.Date._rtd(Math.asin(ilib.Date._dsin(epsilon) * ilib.Date._dsin(ret.apparentLong)));
12498 	//document.debug.log.value += "ret.apparentDecliation = " + ret.apparentDecliation + "\n";
12499 
12500 	// Angular quantities are expressed in decimal degrees
12501 	return ret;
12502 };
12503 
12504 /**
12505  * Calculate the nutation in longitude, deltaPsi, and obliquity, 
12506  * deltaEpsilon for a given Julian date jd. Results are returned as an object
12507  * giving deltaPsi and deltaEpsilon in degrees.
12508  * 
12509  * @static
12510  * @param {number} jd calculate the nutation of this Julian Day
12511  * @return {Object} the deltaPsi and deltaEpsilon of the nutation
12512  */
12513 ilib.Date._nutation = function(jd) {
12514 	var i, j, 
12515 		t = (jd - 2451545.0) / 36525.0, 
12516 		t2, t3, to10, 
12517 		ta = [], 
12518 		dp = 0, 
12519 		de = 0, 
12520 		ang,
12521 		ret = {};
12522 
12523 	t3 = t * (t2 = t * t);
12524 
12525 	/*
12526 	 * Calculate angles. The correspondence between the elements of our array
12527 	 * and the terms cited in Meeus are:
12528 	 * 
12529 	 * ta[0] = D ta[0] = M ta[2] = M' ta[3] = F ta[4] = \Omega
12530 	 * 
12531 	 */
12532 
12533 	ta[0] = ilib.Date._dtr(297.850363 + 445267.11148 * t - 0.0019142 * t2 + t3 / 189474.0);
12534 	ta[1] = ilib.Date._dtr(357.52772 + 35999.05034 * t - 0.0001603 * t2 - t3 / 300000.0);
12535 	ta[2] = ilib.Date._dtr(134.96298 + 477198.867398 * t + 0.0086972 * t2 + t3 / 56250.0);
12536 	ta[3] = ilib.Date._dtr(93.27191 + 483202.017538 * t - 0.0036825 * t2 + t3 / 327270);
12537 	ta[4] = ilib.Date._dtr(125.04452 - 1934.136261 * t + 0.0020708 * t2 + t3 / 450000.0);
12538 
12539 	/*
12540 	 * Range reduce the angles in case the sine and cosine functions don't do it
12541 	 * as accurately or quickly.
12542 	 */
12543 
12544 	for (i = 0; i < 5; i++) {
12545 		ta[i] = ilib.Date._fixangr(ta[i]);
12546 	}
12547 
12548 	to10 = t / 10.0;
12549 	for (i = 0; i < 63; i++) {
12550 		ang = 0;
12551 		for (j = 0; j < 5; j++) {
12552 			if (ilib.data.astro._nutArgMult[(i * 5) + j] != 0) {
12553 				ang += ilib.data.astro._nutArgMult[(i * 5) + j] * ta[j];
12554 			}
12555 		}
12556 		dp += (ilib.data.astro._nutArgCoeff[(i * 4) + 0] + ilib.data.astro._nutArgCoeff[(i * 4) + 1] * to10) * Math.sin(ang);
12557 		de += (ilib.data.astro._nutArgCoeff[(i * 4) + 2] + ilib.data.astro._nutArgCoeff[(i * 4) + 3] * to10) * Math.cos(ang);
12558 	}
12559 
12560 	/*
12561 	 * Return the result, converting from ten thousandths of arc seconds to
12562 	 * radians in the process.
12563 	 */
12564 
12565 	ret.deltaPsi = dp / (3600.0 * 10000.0);
12566 	ret.deltaEpsilon = de / (3600.0 * 10000.0);
12567 
12568 	return ret;
12569 };
12570 
12571 /**
12572  * Returns the equation of time as a fraction of a day.
12573  * 
12574  * @static
12575  * @param {number} jd the Julian Day of the day to calculate for
12576  * @return {number} the equation of time for the given day  
12577  */
12578 ilib.Date._equationOfTime = function(jd) {
12579 	var alpha, deltaPsi, E, epsilon, L0, tau, pos;
12580 
12581 	// 2451545.0 is the Julian day of J2000 epoch
12582 	// 365250.0 is the number of days in a Julian millenium
12583 	tau = (jd - 2451545.0) / 365250.0;
12584 	//console.log("equationOfTime.  tau = " + tau);
12585 	L0 = 280.4664567 + (360007.6982779 * tau) + (0.03032028 * tau * tau)
12586 			+ ((tau * tau * tau) / 49931)
12587 			+ (-((tau * tau * tau * tau) / 15300))
12588 			+ (-((tau * tau * tau * tau * tau) / 2000000));
12589 	//console.log("L0 = " + L0);
12590 	L0 = ilib.Date._fixangle(L0);
12591 	//console.log("L0 = " + L0);
12592 	pos = ilib.Date._sunpos(jd);
12593 	alpha = pos.apparentRightAscension;
12594 	//console.log("alpha = " + alpha);
12595 	var nut = ilib.Date._nutation(jd);
12596 	deltaPsi = nut.deltaPsi;
12597 	//console.log("deltaPsi = " + deltaPsi);
12598 	epsilon = ilib.Date._obliqeq(jd) + nut.deltaEpsilon;
12599 	//console.log("epsilon = " + epsilon);
12600 	//console.log("L0 - 0.0057183 = " + (L0 - 0.0057183));
12601 	//console.log("L0 - 0.0057183 - alpha = " + (L0 - 0.0057183 - alpha));
12602 	//console.log("deltaPsi * cos(epsilon) = " + deltaPsi * ilib.Date._dcos(epsilon));
12603 	
12604 	E = L0 - 0.0057183 - alpha + deltaPsi * ilib.Date._dcos(epsilon);
12605 	// if alpha and L0 are in different quadrants, then renormalize
12606 	// so that the difference between them is in the right range
12607 	if (E > 180) {
12608 		E -= 360;
12609 	}
12610 	//console.log("E = " + E);
12611 	// E = E - 20.0 * (Math.floor(E / 20.0));
12612 	E = E * 4;
12613 	//console.log("Efixed = " + E);
12614 	E = E / (24 * 60);
12615 	//console.log("Eday = " + E);
12616 
12617 	return E;
12618 };
12619 
12620 /**
12621  * @private
12622  * @static
12623  */
12624 ilib.Date._poly = function(x, coefficients) {
12625 	var result = coefficients[0];
12626 	var xpow = x;
12627 	for (var i = 1; i < coefficients.length; i++) {
12628 		result += coefficients[i] * xpow;
12629 		xpow *= x;
12630 	}
12631 	return result;
12632 };
12633 
12634 /**
12635  * Calculate the UTC RD from the local RD given "zone" number of minutes
12636  * worth of offset.
12637  * 
12638  * @static
12639  * @param {number} local RD of the locale time, given in any calendar
12640  * @param {number} zone number of minutes of offset from UTC for the time zone 
12641  * @return {number} the UTC equivalent of the local RD
12642  */
12643 ilib.Date._universalFromLocal = function(local, zone) {
12644 	return local - zone / 1440;
12645 };
12646 
12647 /**
12648  * Calculate the local RD from the UTC RD given "zone" number of minutes
12649  * worth of offset.
12650  * 
12651  * @static
12652  * @param {number} local RD of the locale time, given in any calendar
12653  * @param {number} zone number of minutes of offset from UTC for the time zone 
12654  * @return {number} the UTC equivalent of the local RD
12655  */
12656 ilib.Date._localFromUniversal = function(local, zone) {
12657 	return local + zone / 1440;
12658 };
12659 
12660 /**
12661  * @private
12662  * @static
12663  * @param {number} c julian centuries of the date to calculate
12664  * @return {number} the aberration
12665  */
12666 ilib.Date._aberration = function(c) {
12667 	return 9.74e-05 * ilib.Date._dcos(177.63 + 35999.01847999999 * c) - 0.005575;
12668 };
12669 
12670 /**
12671  * @private
12672  *
12673 ilib.data.astro._nutCoeffA = [124.90, -1934.134, 0.002063];
12674 ilib.data.astro._nutCoeffB = [201.11, 72001.5377, 0.00057];
12675 */
12676 
12677 /**
12678  * @private
12679  * @static
12680  * @param {number} c julian centuries of the date to calculate
12681  * @return {number} the nutation for the given julian century in radians
12682  */
12683 ilib.Date._nutation2 = function(c) {
12684 	var a = ilib.Date._poly(c, ilib.data.astro._nutCoeffA);
12685 	var b = ilib.Date._poly(c, ilib.data.astro._nutCoeffB);
12686 	// return -0.0000834 * ilib.Date._dsin(a) - 0.0000064 * ilib.Date._dsin(b);
12687 	return -0.004778 * ilib.Date._dsin(a) - 0.0003667 * ilib.Date._dsin(b);
12688 };
12689 
12690 
12691 /**
12692  * @static
12693  * @private
12694  */
12695 ilib.Date._ephemerisCorrection = function(jd) {
12696 	var year = ilib.Date.GregDate._calcYear(jd - 1721424.5);
12697 	
12698 	if (1988 <= year && year <= 2019) {
12699 		return (year - 1933) / 86400;
12700 	}
12701 	
12702 	if (1800 <= year && year <= 1987) {
12703 		var jul1 = new ilib.Date.GregRataDie({
12704 			year: year,
12705 			month: 7,
12706 			day: 1,
12707 			hour: 0,
12708 			minute: 0,
12709 			second: 0
12710 		});
12711 		// 693596 is the rd of Jan 1, 1900
12712 		var theta = (jul1.getRataDie() - 693596) / 36525;
12713 		return ilib.Date._poly(theta, (1900 <= year) ? ilib.data.astro._coeff19th : ilib.data.astro._coeff18th);
12714 	}
12715 	
12716 	if (1620 <= year && year <= 1799) {
12717 		year -= 1600;
12718 		return (196.58333 - 4.0675 * year + 0.0219167 * year * year) / 86400;
12719 	}
12720 	
12721 	// 660724 is the rd of Jan 1, 1810
12722 	var jan1 = new ilib.Date.GregRataDie({
12723 		year: year,
12724 		month: 1,
12725 		day: 1,
12726 		hour: 0,
12727 		minute: 0,
12728 		second: 0
12729 	});
12730 	// var x = 0.5 + (jan1.getRataDie() - 660724);
12731 	var x = 0.5 + (jan1.getRataDie() - 660724);
12732 	
12733 	return ((x * x / 41048480) - 15) / 86400;
12734 };
12735 
12736 /**
12737  * @static
12738  * @private
12739  */
12740 ilib.Date._ephemerisFromUniversal = function(jd) {
12741 	return jd + ilib.Date._ephemerisCorrection(jd);
12742 };
12743 
12744 /**
12745  * @static
12746  * @private
12747  */
12748 ilib.Date._universalFromEphemeris = function(jd) {
12749 	return jd - ilib.Date._ephemerisCorrection(jd);
12750 };
12751 
12752 /**
12753  * @static
12754  * @private
12755  */
12756 ilib.Date._julianCenturies = function(jd) {
12757 	// 2451545.0 is the Julian day of J2000 epoch
12758 	// 730119.5 is the Gregorian RD of J2000 epoch
12759 	// 36525.0 is the number of days in a Julian century
12760 	return (ilib.Date._ephemerisFromUniversal(jd) - 2451545.0) / 36525.0;
12761 };
12762 
12763 /**
12764  * Calculate the solar longitude
12765  * 
12766  * @static
12767  * @param {number} jd julian day of the date to calculate the longitude for 
12768  * @return {number} the solar longitude in degrees
12769  */
12770 ilib.Date._solarLongitude = function(jd) {
12771 	var c = ilib.Date._julianCenturies(jd),
12772 		longitude = 0,
12773 		len = ilib.data.astro._solarLongCoeff.length,
12774 		row;
12775 	
12776 	for (var i = 0; i < len; i++) {
12777 		longitude += ilib.data.astro._solarLongCoeff[i] * 
12778 			ilib.Date._dsin(ilib.data.astro._solarLongAddends[i] + ilib.data.astro._solarLongMultipliers[i] * c);
12779 	}
12780 	longitude *= 5.729577951308232e-06;
12781 	longitude += 282.77718340000001 + 36000.769537439999 * c;
12782 	longitude += ilib.Date._aberration(c) + ilib.Date._nutation2(c);
12783 	return ilib.Date._fixangle(longitude);
12784 };
12785 
12786 /**
12787  * @static
12788  * @protected
12789  * @param {number} jd
12790  * @return {number}
12791  */
12792 ilib.Date._lunarLongitude = function (jd) {
12793 	var c = ilib.Date._julianCenturies(jd),
12794 	    meanMoon = ilib.Date._fixangle(ilib.Date._poly(c, ilib.data.astro._meanMoonCoeff)),
12795 	    elongation = ilib.Date._fixangle(ilib.Date._poly(c, ilib.data.astro._elongationCoeff)),
12796 	    solarAnomaly = ilib.Date._fixangle(ilib.Date._poly(c, ilib.data.astro._solarAnomalyCoeff)),
12797 	    lunarAnomaly = ilib.Date._fixangle(ilib.Date._poly(c, ilib.data.astro._lunarAnomalyCoeff)),
12798 	    moonNode = ilib.Date._fixangle(ilib.Date._poly(c, ilib.data.astro._moonFromNodeCoeff)),
12799 	    e = ilib.Date._poly(c, ilib.data.astro._eCoeff);
12800 	
12801 	var sum = 0;
12802 	for (var i = 0; i < ilib.data.astro._lunarElongationLongCoeff.length; i++) {
12803 		var x = ilib.data.astro._solarAnomalyLongCoeff[i];
12804 
12805 		sum += ilib.data.astro._sineCoeff[i] * Math.pow(e, Math.abs(x)) * 
12806 			ilib.Date._dsin(ilib.data.astro._lunarElongationLongCoeff[i] * elongation + x * solarAnomaly + 
12807 				ilib.data.astro._lunarAnomalyLongCoeff[i] * lunarAnomaly + 
12808 				ilib.data.astro._moonFromNodeLongCoeff[i] * moonNode);
12809 	}
12810 	var longitude = sum / 1000000;
12811 	var venus = 3958.0 / 1000000 * ilib.Date._dsin(119.75 + c * 131.84899999999999);
12812 	var jupiter = 318.0 / 1000000 * ilib.Date._dsin(53.090000000000003 + c * 479264.28999999998);
12813 	var flatEarth = 1962.0 / 1000000 * ilib.Date._dsin(meanMoon - moonNode);
12814 	
12815 	return ilib.Date._fixangle(meanMoon + longitude + venus + jupiter + flatEarth + ilib.Date._nutation2(c));
12816 };
12817 
12818 /**
12819  * @static
12820  * @param {number} n
12821  * @return {number} julian day of the n'th new moon
12822  */
12823 ilib.Date._newMoonTime = function(n) {
12824 	var k = n - 24724;
12825 	var c = k / 1236.8499999999999;
12826 	var approx = ilib.Date._poly(c, ilib.data.astro._nmApproxCoeff);
12827 	var capE = ilib.Date._poly(c, ilib.data.astro._nmCapECoeff);
12828 	var solarAnomaly = ilib.Date._poly(c, ilib.data.astro._nmSolarAnomalyCoeff);
12829 	var lunarAnomaly = ilib.Date._poly(c, ilib.data.astro._nmLunarAnomalyCoeff);
12830 	var moonArgument = ilib.Date._poly(c, ilib.data.astro._nmMoonArgumentCoeff);
12831 	var capOmega = ilib.Date._poly(c, ilib.data.astro._nmCapOmegaCoeff);
12832 	var correction = -0.00017 * ilib.Date._dsin(capOmega);
12833 	for (var i = 0; i < ilib.data.astro._nmSineCoeff.length; i++) {
12834 		correction = correction + ilib.data.astro._nmSineCoeff[i] * Math.pow(capE, ilib.data.astro._nmEFactor[i]) * 
12835 		ilib.Date._dsin(ilib.data.astro._nmSolarCoeff[i] * solarAnomaly + 
12836 				ilib.data.astro._nmLunarCoeff[i] * lunarAnomaly + 
12837 				ilib.data.astro._nmMoonCoeff[i] * moonArgument);
12838 	}
12839 	var additional = 0;
12840 	for (var i = 0; i < ilib.data.astro._nmAddConst.length; i++) {
12841 		additional = additional + ilib.data.astro._nmAddFactor[i] * 
12842 		ilib.Date._dsin(ilib.data.astro._nmAddConst[i] + ilib.data.astro._nmAddCoeff[i] * k);
12843 	}
12844 	var extra = 0.000325 * ilib.Date._dsin(ilib.Date._poly(c, ilib.data.astro._nmExtra));
12845 	return ilib.Date._universalFromEphemeris(approx + correction + extra + additional + ilib.Date.RataDie.gregorianEpoch);
12846 };
12847 
12848 /**
12849  * @static
12850  * @param {number} jd
12851  * @return {number}
12852  */
12853 ilib.Date._lunarSolarAngle = function(jd) {
12854 	var lunar = ilib.Date._lunarLongitude(jd);
12855 	var solar = ilib.Date._solarLongitude(jd)
12856 	return ilib.Date._fixangle(lunar - solar);
12857 };
12858 
12859 /**
12860  * @static
12861  * @param {number} jd
12862  * @return {number}
12863  */
12864 ilib.Date._newMoonBefore = function (jd) {
12865 	var phase = ilib.Date._lunarSolarAngle(jd);
12866 	// 11.450086114414322 is the julian day of the 0th full moon
12867 	// 29.530588853000001 is the average length of a month
12868 	var guess = Math.round((jd - 11.450086114414322 - ilib.Date.RataDie.gregorianEpoch) / 29.530588853000001 - phase / 360) - 1;
12869 	var current, last;
12870 	current = last = ilib.Date._newMoonTime(guess);
12871 	while (current < jd) {
12872 		guess++;
12873 		last = current;
12874 		current = ilib.Date._newMoonTime(guess);
12875 	}
12876 	return last;
12877 };
12878 
12879 /**
12880  * @static
12881  * @param {number} jd
12882  * @return {number}
12883  */
12884 ilib.Date._newMoonAtOrAfter = function (jd) {
12885 	var phase = ilib.Date._lunarSolarAngle(jd);
12886 	// 11.450086114414322 is the julian day of the 0th full moon
12887 	// 29.530588853000001 is the average length of a month
12888 	var guess = Math.round((jd - 11.450086114414322 - ilib.Date.RataDie.gregorianEpoch) / 29.530588853000001 - phase / 360);
12889 	var current;
12890 	while ((current = ilib.Date._newMoonTime(guess)) < jd) {
12891 		guess++;
12892 	}
12893 	return current;
12894 };
12895 
12896 /**
12897  * @static
12898  * @param {number} jd JD to calculate from
12899  * @param {number} longitude longitude to seek 
12900  * @returns {number} the JD of the next time that the solar longitude 
12901  * is a multiple of the given longitude
12902  */
12903 ilib.Date._nextSolarLongitude = function(jd, longitude) {
12904 	var rate = 365.242189 / 360.0;
12905 	var tau = jd + rate * ilib.Date._fixangle(longitude - ilib.Date._solarLongitude(jd));
12906 	var start = Math.max(jd, tau - 5.0);
12907 	var end = tau + 5.0;
12908 	
12909 	return ilib.bisectionSearch(0, start, end, 1e-6, function (l) {
12910 		return 180 - ilib.Date._fixangle(ilib.Date._solarLongitude(l) - longitude);
12911 	});
12912 };
12913 
12914 /**
12915  * Floor the julian day to midnight of the current julian day.
12916  * 
12917  * @static
12918  * @protected
12919  * @param {number} jd the julian to round
12920  * @return {number} the jd floored to the midnight of the julian day
12921  */
12922 ilib.Date._floorToJD = function(jd) {
12923 	return Math.floor(jd - 0.5) + 0.5;
12924 };
12925 
12926 /**
12927  * Floor the julian day to midnight of the current julian day.
12928  * 
12929  * @static
12930  * @protected
12931  * @param {number} jd the julian to round
12932  * @return {number} the jd floored to the midnight of the julian day
12933  */
12934 ilib.Date._ceilToJD = function(jd) {
12935 	return Math.ceil(jd + 0.5) - 0.5;
12936 };
12937 
12938 /*
12939  * persratadie.js - Represent a rata die date in the Persian calendar
12940  * 
12941  * Copyright © 2014, JEDLSoft
12942  *
12943  * Licensed under the Apache License, Version 2.0 (the "License");
12944  * you may not use this file except in compliance with the License.
12945  * You may obtain a copy of the License at
12946  *
12947  *     http://www.apache.org/licenses/LICENSE-2.0
12948  *
12949  * Unless required by applicable law or agreed to in writing, software
12950  * distributed under the License is distributed on an "AS IS" BASIS,
12951  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12952  *
12953  * See the License for the specific language governing permissions and
12954  * limitations under the License.
12955  */
12956 
12957 /* !depends 
12958 date.js
12959 util/utils.js
12960 util/math.js
12961 calendar/ratadie.js
12962 calendar/astro.js
12963 calendar/gregoriandate.js
12964 */
12965 
12966 /**
12967  * Construct a new Persian RD date number object. The constructor parameters can 
12968  * contain any of the following properties:
12969  * 
12970  * <ul>
12971  * <li><i>unixtime<i> - sets the time of this instance according to the given 
12972  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970, Gregorian
12973  * 
12974  * <li><i>julianday</i> - sets the time of this instance according to the given
12975  * Julian Day instance or the Julian Day given as a float
12976  * 
12977  * <li><i>year</i> - any integer, including 0
12978  * 
12979  * <li><i>month</i> - 1 to 12, where 1 means Farvardin, 2 means Ordibehesht, etc.
12980  * 
12981  * <li><i>day</i> - 1 to 31
12982  * 
12983  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
12984  * is always done with an unambiguous 24 hour representation
12985  * 
12986  * <li><i>minute</i> - 0 to 59
12987  * 
12988  * <li><i>second</i> - 0 to 59
12989  * 
12990  * <li><i>millisecond</i> - 0 to 999
12991  * 
12992  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
12993  * </ul>
12994  *
12995  * If the constructor is called with another Persian date instance instead of
12996  * a parameter block, the other instance acts as a parameter block and its
12997  * settings are copied into the current instance.<p>
12998  * 
12999  * If the constructor is called with no arguments at all or if none of the 
13000  * properties listed above are present, then the RD is calculate based on 
13001  * the current date at the time of instantiation. <p>
13002  * 
13003  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
13004  * specified in the params, it is assumed that they have the smallest possible
13005  * value in the range for the property (zero or one).<p>
13006  * 
13007  * Depends directive: !depends persiandate.js
13008  * 
13009  * @private
13010  * @class
13011  * @constructor
13012  * @extends ilib.Date.RataDie
13013  * @param {Object=} params parameters that govern the settings and behaviour of this Persian RD date
13014  */
13015 ilib.Date.PersAstroRataDie = function(params) {
13016 	this.rd = undefined;
13017 	ilib.Date.initAstro(
13018 		params && typeof(params.sync) === 'boolean' ? params.sync : true,
13019 		params && params.loadParams,
13020 		ilib.bind(this, function (x) {
13021 			ilib.Date.RataDie.call(this, params);
13022 			if (params && typeof(params.callback) === 'function') {
13023 				params.callback(this);
13024 			}
13025 		})
13026 	);
13027 };
13028 
13029 ilib.Date.PersAstroRataDie.prototype = new ilib.Date.RataDie();
13030 ilib.Date.PersAstroRataDie.prototype.parent = ilib.Date.RataDie;
13031 ilib.Date.PersAstroRataDie.prototype.constructor = ilib.Date.PersAstroRataDie;
13032 
13033 /**
13034  * The difference between a zero Julian day and the first Persian date
13035  * @private
13036  * @const
13037  * @type number
13038  */
13039 ilib.Date.PersAstroRataDie.prototype.epoch = 1948319.5;
13040 
13041 /**
13042  * @protected 
13043  */
13044 ilib.Date.PersAstroRataDie.prototype._tehranEquinox = function(year) {
13045     var equJED, equJD, equAPP, equTehran, dtTehran, eot;
13046 
13047     //  March equinox in dynamical time
13048     equJED = ilib.Date._equinox(year, 0);
13049 
13050     //  Correct for delta T to obtain Universal time
13051     equJD = equJED - (ilib.Date._deltat(year) / (24 * 60 * 60));
13052 
13053     //  Apply the equation of time to yield the apparent time at Greenwich
13054     eot = ilib.Date._equationOfTime(equJED) * 360;
13055     eot = (eot - 20 * Math.floor(eot/20)) / 360;
13056     equAPP = equJD + eot;
13057 
13058     /*  
13059      * Finally, we must correct for the constant difference between
13060      * the Greenwich meridian and the time zone standard for Iran 
13061      * Standard time, 52 degrees 30 minutes to the East.
13062      */
13063 
13064     dtTehran = 52.5 / 360;
13065     equTehran = equAPP + dtTehran;
13066 
13067     return equTehran;
13068 };
13069 
13070 /**
13071  * Calculate the year based on the given Julian day.
13072  * @protected
13073  * @param {number} jd the Julian day to get the year for
13074  * @return {{year:number,equinox:number}} the year and the last equinox
13075  */
13076 ilib.Date.PersAstroRataDie.prototype._getYear = function(jd) {
13077 	var gd = new ilib.Date.GregDate({julianday: jd});
13078     var guess = gd.getYears() - 2,
13079     	nexteq,
13080     	ret = {};
13081 
13082     //ret.equinox = Math.floor(this._tehranEquinox(guess));
13083     ret.equinox = this._tehranEquinox(guess);
13084 	while (ret.equinox > jd) {
13085 	    guess--;
13086 	    // ret.equinox = Math.floor(this._tehranEquinox(guess));
13087 	    ret.equinox = this._tehranEquinox(guess);
13088 	}
13089 	nexteq = ret.equinox - 1;
13090 	// if the equinox falls after noon, then the day after that is the start of the 
13091 	// next year, so truncate the JD to get the noon of the day before the day with 
13092 	//the equinox on it, then add 0.5 to get the midnight of that day 
13093 	while (!(Math.floor(ret.equinox) + 0.5 <= jd && jd < Math.floor(nexteq) + 0.5)) {
13094 	    ret.equinox = nexteq;
13095 	    guess++;
13096 	    // nexteq = Math.floor(this._tehranEquinox(guess));
13097 	    nexteq = this._tehranEquinox(guess);
13098 	}
13099 	
13100 	// Mean solar tropical year is 365.24219878 days
13101 	ret.year = Math.round((ret.equinox - this.epoch - 1) / 365.24219878) + 1;
13102 	
13103 	return ret;
13104 };
13105 
13106 /**
13107  * Calculate the Rata Die (fixed day) number of the given date from the
13108  * date components.
13109  *
13110  * @protected
13111  * @param {Object} date the date components to calculate the RD from
13112  */
13113 ilib.Date.PersAstroRataDie.prototype._setDateComponents = function(date) {
13114     var adr, guess, jd;
13115 
13116     // Mean solar tropical year is 365.24219878 days 
13117     guess = this.epoch + 1 + 365.24219878 * (date.year - 2);
13118     adr = {year: date.year - 1, equinox: 0};
13119 
13120     while (adr.year < date.year) {
13121         adr = this._getYear(guess);
13122         guess = adr.equinox + (365.24219878 + 2);
13123     }
13124 
13125     jd = Math.floor(adr.equinox) +
13126             ((date.month <= 7) ?
13127                 ((date.month - 1) * 31) :
13128                 (((date.month - 1) * 30) + 6)
13129             ) +
13130     	    (date.day - 1 + 0.5); // add 0.5 so that we convert JDs, which start at noon to RDs which start at midnight
13131     
13132 	jd += (date.hour * 3600000 +
13133 			date.minute * 60000 +
13134 			date.second * 1000 +
13135 			date.millisecond) /
13136 			86400000;
13137 
13138     this.rd = jd - this.epoch;
13139 };
13140 
13141 /**
13142  * Return the rd number of the particular day of the week on or before the 
13143  * given rd. eg. The Sunday on or before the given rd.
13144  * @private
13145  * @param {number} rd the rata die date of the reference date
13146  * @param {number} dayOfWeek the day of the week that is being sought relative 
13147  * to the current date
13148  * @return {number} the rd of the day of the week
13149  */
13150 ilib.Date.PersAstroRataDie.prototype._onOrBefore = function(rd, dayOfWeek) {
13151 	return rd - ilib.mod(Math.floor(rd) - dayOfWeek - 3, 7);
13152 };
13153 
13154 /*
13155  * persianastro.js - Represent a Persian astronomical (Hijjri) calendar object.
13156  * 
13157  * Copyright © 2014, JEDLSoft
13158  *
13159  * Licensed under the Apache License, Version 2.0 (the "License");
13160  * you may not use this file except in compliance with the License.
13161  * You may obtain a copy of the License at
13162  *
13163  *     http://www.apache.org/licenses/LICENSE-2.0
13164  *
13165  * Unless required by applicable law or agreed to in writing, software
13166  * distributed under the License is distributed on an "AS IS" BASIS,
13167  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13168  *
13169  * See the License for the specific language governing permissions and
13170  * limitations under the License.
13171  */
13172 
13173 
13174 /* !depends 
13175 calendar/astro.js 
13176 calendar.js 
13177 locale.js 
13178 date.js 
13179 julianday.js 
13180 util/utils.js
13181 calendar/persratadie.js 
13182 */
13183 
13184 /**
13185  * @class
13186  * Construct a new Persian astronomical (Hijjri) calendar object. This class encodes 
13187  * information about a Persian calendar. This class differs from the 
13188  * Persian calendar in that the leap years are calculated based on the
13189  * astronomical observations of the sun in Teheran, instead of calculating
13190  * the leap years based on a regular cyclical rhythm algorithm.<p>
13191  * 
13192  * Depends directive: !depends persianastro.js
13193  * 
13194  * @constructor
13195  * @implements ilib.Cal
13196  */
13197 ilib.Cal.Persian = function() {
13198 	this.type = "persian";
13199 };
13200 
13201 /**
13202  * @private
13203  * @const
13204  * @type Array.<number> 
13205  * the lengths of each month 
13206  */
13207 ilib.Cal.Persian.monthLengths = [
13208 	31,  // Farvardin
13209 	31,  // Ordibehesht
13210 	31,  // Khordad
13211 	31,  // Tir
13212 	31,  // Mordad
13213 	31,  // Shahrivar
13214 	30,  // Mehr
13215 	30,  // Aban
13216 	30,  // Azar
13217 	30,  // Dey
13218 	30,  // Bahman
13219 	29   // Esfand
13220 ];
13221 
13222 /**
13223  * Return the number of months in the given year. The number of months in a year varies
13224  * for some luni-solar calendars because in some years, an extra month is needed to extend the 
13225  * days in a year to an entire solar year. The month is represented as a 1-based number
13226  * where 1=first month, 2=second month, etc.
13227  * 
13228  * @param {number} year a year for which the number of months is sought
13229  * @return {number} The number of months in the given year
13230  */
13231 ilib.Cal.Persian.prototype.getNumMonths = function(year) {
13232 	return 12;
13233 };
13234 
13235 /**
13236  * Return the number of days in a particular month in a particular year. This function
13237  * can return a different number for a month depending on the year because of things
13238  * like leap years.
13239  * 
13240  * @param {number} month the month for which the length is sought
13241  * @param {number} year the year within which that month can be found
13242  * @return {number} the number of days within the given month in the given year
13243  */
13244 ilib.Cal.Persian.prototype.getMonLength = function(month, year) {
13245 	if (month !== 12 || !this.isLeapYear(year)) {
13246 		return ilib.Cal.Persian.monthLengths[month-1];
13247 	} else {
13248 		// Month 12, Esfand, has 30 days instead of 29 in leap years
13249 		return 30;
13250 	}
13251 };
13252 
13253 /**
13254  * Return true if the given year is a leap year in the Persian astronomical calendar.
13255  * @param {number} year the year for which the leap year information is being sought
13256  * @return {boolean} true if the given year is a leap year
13257  */
13258 ilib.Cal.Persian.prototype.isLeapYear = function(year) {
13259 	var rdNextYear = new ilib.Date.PersAstroRataDie({
13260 		cal: this,
13261 		year: year + 1,
13262 		month: 1,
13263 		day: 1,
13264 		hour: 0,
13265 		minute: 0,
13266 		second: 0,
13267 		millisecond: 0
13268 	});
13269 	var rdThisYear = new ilib.Date.PersAstroRataDie({
13270 		cal: this,
13271 		year: year,
13272 		month: 1,
13273 		day: 1,
13274 		hour: 0,
13275 		minute: 0,
13276 		second: 0,
13277 		millisecond: 0
13278 	}); 
13279     return (rdNextYear.getRataDie() - rdThisYear.getRataDie()) > 365;
13280 };
13281 
13282 /**
13283  * Return the type of this calendar.
13284  * 
13285  * @return {string} the name of the type of this calendar 
13286  */
13287 ilib.Cal.Persian.prototype.getType = function() {
13288 	return this.type;
13289 };
13290 
13291 /**
13292  * Return a date instance for this calendar type using the given
13293  * options.
13294  * @param {Object} options options controlling the construction of 
13295  * the date instance
13296  * @return {ilib.Date} a date appropriate for this calendar type
13297  */
13298 ilib.Cal.Persian.prototype.newDateInstance = function (options) {
13299 	return new ilib.Date.PersDate(options);
13300 };
13301 
13302 /* register this calendar for the factory method */
13303 ilib.Cal._constructors["persian"] = ilib.Cal.Persian;
13304 
13305 /*
13306  * persianastrodate.js - Represent a date in the Persian astronomical (Hijjri) calendar
13307  * 
13308  * Copyright © 2014, JEDLSoft
13309  *
13310  * Licensed under the Apache License, Version 2.0 (the "License");
13311  * you may not use this file except in compliance with the License.
13312  * You may obtain a copy of the License at
13313  *
13314  *     http://www.apache.org/licenses/LICENSE-2.0
13315  *
13316  * Unless required by applicable law or agreed to in writing, software
13317  * distributed under the License is distributed on an "AS IS" BASIS,
13318  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13319  *
13320  * See the License for the specific language governing permissions and
13321  * limitations under the License.
13322  */
13323 
13324 /* !depends 
13325 date.js
13326 calendar/persratadie.js
13327 calendar/persianastro.js 
13328 util/utils.js
13329 util/search.js
13330 util/math.js
13331 localeinfo.js 
13332 julianday.js 
13333 */
13334 
13335 // !data astro
13336 
13337 /**
13338  * @class
13339  * 
13340  * Construct a new Persian astronomical date object. The constructor parameters can 
13341  * contain any of the following properties:
13342  * 
13343  * <ul>
13344  * <li><i>unixtime<i> - sets the time of this instance according to the given 
13345  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970, Gregorian
13346  * 
13347  * <li><i>julianday</i> - sets the time of this instance according to the given
13348  * Julian Day instance or the Julian Day given as a float
13349  * 
13350  * <li><i>year</i> - any integer, including 0
13351  * 
13352  * <li><i>month</i> - 1 to 12, where 1 means Farvardin, 2 means Ordibehesht, etc.
13353  * 
13354  * <li><i>day</i> - 1 to 31
13355  * 
13356  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
13357  * is always done with an unambiguous 24 hour representation
13358  * 
13359  * <li><i>minute</i> - 0 to 59
13360  * 
13361  * <li><i>second</i> - 0 to 59
13362  * 
13363  * <li><i>millisecond</i> - 0 to 999
13364  * 
13365  * <li><i>timezone</i> - the ilib.TimeZone instance or time zone name as a string 
13366  * of this persian date. The date/time is kept in the local time. The time zone
13367  * is used later if this date is formatted according to a different time zone and
13368  * the difference has to be calculated, or when the date format has a time zone
13369  * component in it.
13370  * 
13371  * <li><i>locale</i> - locale for this persian date. If the time zone is not 
13372  * given, it can be inferred from this locale. For locales that span multiple
13373  * time zones, the one with the largest population is chosen as the one that 
13374  * represents the locale.
13375  * 
13376  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
13377  * </ul>
13378  *
13379  * If the constructor is called with another Persian date instance instead of
13380  * a parameter block, the other instance acts as a parameter block and its
13381  * settings are copied into the current instance.<p>
13382  * 
13383  * If the constructor is called with no arguments at all or if none of the 
13384  * properties listed above 
13385  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
13386  * components are 
13387  * filled in with the current date at the time of instantiation. Note that if
13388  * you do not give the time zone when defaulting to the current time and the 
13389  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
13390  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
13391  * Mean Time").<p>
13392  * 
13393  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
13394  * specified in the params, it is assumed that they have the smallest possible
13395  * value in the range for the property (zero or one).<p>
13396  * 
13397  * Depends directive: !depends persiandate.js
13398  * 
13399  * @constructor
13400  * @extends ilib.Date
13401  * @param {Object=} params parameters that govern the settings and behaviour of this Persian date
13402  */
13403 ilib.Date.PersDate = function(params) {
13404 	this.cal = new ilib.Cal.Persian();
13405 	this.timezone = "local";
13406 	
13407 	if (params) {
13408 		if (params.locale) {
13409 			this.locale = (typeof(params.locale) === 'string') ? new ilib.Locale(params.locale) : params.locale;
13410 			var li = new ilib.LocaleInfo(this.locale);
13411 			this.timezone = li.getTimeZone(); 
13412 		}
13413 		if (params.timezone) {
13414 			this.timezone = params.timezone;
13415 		}
13416 	}
13417 	
13418 	ilib.Date.initAstro(
13419 		params && typeof(params.sync) === 'boolean' ? params.sync : true,
13420 		params && params.loadParams,
13421 		ilib.bind(this, function (x) {
13422 			if (params && (params.year || params.month || params.day || params.hour ||
13423 					params.minute || params.second || params.millisecond)) {
13424 				/**
13425 				 * Year in the Persian calendar.
13426 				 * @type number
13427 				 */
13428 				this.year = parseInt(params.year, 10) || 0;
13429 
13430 				/**
13431 				 * The month number, ranging from 1 to 12
13432 				 * @type number
13433 				 */
13434 				this.month = parseInt(params.month, 10) || 1;
13435 
13436 				/**
13437 				 * The day of the month. This ranges from 1 to 31.
13438 				 * @type number
13439 				 */
13440 				this.day = parseInt(params.day, 10) || 1;
13441 				
13442 				/**
13443 				 * The hour of the day. This can be a number from 0 to 23, as times are
13444 				 * stored unambiguously in the 24-hour clock.
13445 				 * @type number
13446 				 */
13447 				this.hour = parseInt(params.hour, 10) || 0;
13448 
13449 				/**
13450 				 * The minute of the hours. Ranges from 0 to 59.
13451 				 * @type number
13452 				 */
13453 				this.minute = parseInt(params.minute, 10) || 0;
13454 
13455 				/**
13456 				 * The second of the minute. Ranges from 0 to 59.
13457 				 * @type number
13458 				 */
13459 				this.second = parseInt(params.second, 10) || 0;
13460 
13461 				/**
13462 				 * The millisecond of the second. Ranges from 0 to 999.
13463 				 * @type number
13464 				 */
13465 				this.millisecond = parseInt(params.millisecond, 10) || 0;
13466 				
13467 				/**
13468 				 * The day of the year. Ranges from 1 to 366.
13469 				 * @type number
13470 				 */
13471 				this.dayOfYear = parseInt(params.dayOfYear, 10);
13472 
13473 				if (typeof(params.dst) === 'boolean') {
13474 					this.dst = params.dst;
13475 				}
13476 				
13477 				this.rd = this.newRd(this);
13478 				
13479 				// add the time zone offset to the rd to convert to UTC
13480 				if (!this.tz) {
13481 					this.tz = new ilib.TimeZone({id: this.timezone});
13482 				}
13483 				// getOffsetMillis requires that this.year, this.rd, and this.dst 
13484 				// are set in order to figure out which time zone rules apply and 
13485 				// what the offset is at that point in the year
13486 				this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
13487 				if (this.offset !== 0) {
13488 					this.rd = this.newRd({
13489 						rd: this.rd.getRataDie() - this.offset
13490 					});
13491 				}
13492 			}
13493 			
13494 			if (!this.rd) {
13495 				this.rd = this.newRd(params);
13496 				this._calcDateComponents();
13497 			}
13498 			
13499 			if (params && typeof(params.onLoad) === 'function') {
13500 				params.onLoad(this);
13501 			}
13502 		})
13503 	);
13504 };
13505 
13506 ilib.Date.PersDate.prototype = new ilib.Date({noinstance: true});
13507 ilib.Date.PersDate.prototype.parent = ilib.Date;
13508 ilib.Date.PersDate.prototype.constructor = ilib.Date.PersDate;
13509 
13510 /**
13511  * @private
13512  * @const
13513  * @type Array.<number>
13514  * the cumulative lengths of each month, for a non-leap year 
13515  */
13516 ilib.Date.PersDate.cumMonthLengths = [
13517     0,    // Farvardin
13518 	31,   // Ordibehesht
13519 	62,   // Khordad
13520 	93,   // Tir
13521 	124,  // Mordad
13522 	155,  // Shahrivar
13523 	186,  // Mehr
13524 	216,  // Aban
13525 	246,  // Azar
13526 	276,  // Dey
13527 	306,  // Bahman
13528 	336,  // Esfand
13529 	366
13530 ];
13531 
13532 /**
13533  * Return a new RD for this date type using the given params.
13534  * @protected
13535  * @param {Object=} params the parameters used to create this rata die instance
13536  * @returns {ilib.Date.RataDie} the new RD instance for the given params
13537  */
13538 ilib.Date.PersDate.prototype.newRd = function (params) {
13539 	return new ilib.Date.PersAstroRataDie(params);
13540 };
13541 
13542 /**
13543  * Return the year for the given RD
13544  * @protected
13545  * @param {number} rd RD to calculate from 
13546  * @returns {number} the year for the RD
13547  */
13548 ilib.Date.PersDate.prototype._calcYear = function(rd) {
13549 	var julianday = rd + this.rd.epoch;
13550 	return this.rd._getYear(julianday).year;
13551 };
13552 
13553 /**
13554  * @private
13555  * Calculate date components for the given RD date.
13556  */
13557 ilib.Date.PersDate.prototype._calcDateComponents = function () {
13558 	var remainder,
13559 		rd = this.rd.getRataDie();
13560 	
13561 	this.year = this._calcYear(rd);
13562 	
13563 	if (typeof(this.offset) === "undefined") {
13564 		// now offset the RD by the time zone, then recalculate in case we were 
13565 		// near the year boundary
13566 		if (!this.tz) {
13567 			this.tz = new ilib.TimeZone({id: this.timezone});
13568 		}
13569 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
13570 	}
13571 	
13572 	if (this.offset !== 0) {
13573 		rd += this.offset;
13574 		this.year = this._calcYear(rd);
13575 	}
13576 	
13577 	//console.log("PersDate.calcComponent: calculating for rd " + rd);
13578 	//console.log("PersDate.calcComponent: year is " + ret.year);
13579 	var yearStart = this.newRd({
13580 		year: this.year,
13581 		month: 1,
13582 		day: 1,
13583 		hour: 0,
13584 		minute: 0,
13585 		second: 0,
13586 		millisecond: 0
13587 	});
13588 	remainder = rd - yearStart.getRataDie() + 1;
13589 	
13590 	this.dayOfYear = remainder;
13591 	
13592 	//console.log("PersDate.calcComponent: remainder is " + remainder);
13593 	
13594 	this.month = ilib.bsearch(Math.floor(remainder), ilib.Date.PersDate.cumMonthLengths);
13595 	remainder -= ilib.Date.PersDate.cumMonthLengths[this.month-1];
13596 	
13597 	//console.log("PersDate.calcComponent: month is " + this.month + " and remainder is " + remainder);
13598 	
13599 	this.day = Math.floor(remainder);
13600 	remainder -= this.day;
13601 	
13602 	//console.log("PersDate.calcComponent: day is " + this.day + " and remainder is " + remainder);
13603 	
13604 	// now convert to milliseconds for the rest of the calculation
13605 	remainder = Math.round(remainder * 86400000);
13606 	
13607 	this.hour = Math.floor(remainder/3600000);
13608 	remainder -= this.hour * 3600000;
13609 	
13610 	this.minute = Math.floor(remainder/60000);
13611 	remainder -= this.minute * 60000;
13612 	
13613 	this.second = Math.floor(remainder/1000);
13614 	remainder -= this.second * 1000;
13615 	
13616 	this.millisecond = remainder;
13617 };
13618 
13619 /**
13620  * Return the day of the week of this date. The day of the week is encoded
13621  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
13622  * 
13623  * @return {number} the day of the week
13624  */
13625 ilib.Date.PersDate.prototype.getDayOfWeek = function() {
13626 	var rd = Math.floor(this.getRataDie());
13627 	return ilib.mod(rd-3, 7);
13628 };
13629 
13630 /**
13631  * Return the ordinal day of the year. Days are counted from 1 and proceed linearly up to 
13632  * 365, regardless of months or weeks, etc. That is, Farvardin 1st is day 1, and 
13633  * December 31st is 365 in regular years, or 366 in leap years.
13634  * @return {number} the ordinal day of the year
13635  */
13636 ilib.Date.PersDate.prototype.getDayOfYear = function() {
13637 	return ilib.Date.PersDate.cumMonthLengths[this.month-1] + this.day;
13638 };
13639 
13640 /**
13641  * Return the era for this date as a number. The value for the era for Persian 
13642  * calendars is -1 for "before the persian era" (BP) and 1 for "the persian era" (anno 
13643  * persico or AP). 
13644  * BP dates are any date before Farvardin 1, 1 AP. In the proleptic Persian calendar, 
13645  * there is a year 0, so any years that are negative or zero are BP.
13646  * @return {number} 1 if this date is in the common era, -1 if it is before the 
13647  * common era 
13648  */
13649 ilib.Date.PersDate.prototype.getEra = function() {
13650 	return (this.year < 1) ? -1 : 1;
13651 };
13652 
13653 /**
13654  * Return the name of the calendar that governs this date.
13655  * 
13656  * @return {string} a string giving the name of the calendar
13657  */
13658 ilib.Date.PersDate.prototype.getCalendar = function() {
13659 	return "persian";
13660 };
13661 
13662 // register with the factory method
13663 ilib.Date._constructors["persian"] = ilib.Date.PersDate;
13664 /*
13665  * han.js - Represent a Han Chinese Lunar calendar object.
13666  * 
13667  * Copyright © 2014, JEDLSoft
13668  *
13669  * Licensed under the Apache License, Version 2.0 (the "License");
13670  * you may not use this file except in compliance with the License.
13671  * You may obtain a copy of the License at
13672  *
13673  *     http://www.apache.org/licenses/LICENSE-2.0
13674  *
13675  * Unless required by applicable law or agreed to in writing, software
13676  * distributed under the License is distributed on an "AS IS" BASIS,
13677  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13678  *
13679  * See the License for the specific language governing permissions and
13680  * limitations under the License.
13681  */
13682 
13683 /* !depends calendar.js locale.js date.js julianday.js util/utils.js util/math.js calendar/astro.js */
13684 
13685 /**
13686  * @class
13687  * Construct a new Han algorithmic calendar object. This class encodes information about
13688  * a Han algorithmic calendar.<p>
13689  * 
13690  * Depends directive: !depends han.js
13691  * 
13692  * @constructor
13693  * @param {Object=} params optional parameters to load the calendrical data
13694  * @implements ilib.Cal
13695  */
13696 ilib.Cal.Han = function(params) {
13697 	this.type = "han";
13698 	var sync = params && typeof(params.sync) === 'boolean' ? params.sync : true;
13699 	
13700 	ilib.Date.initAstro(sync, params && params.loadParams, /** @type {function ((Object|null)=): ?} */ ilib.bind(this, function (x) {
13701 		if (params && typeof(params.callback) === 'function') {
13702 			params.callback(this);
13703 		}
13704 	}));
13705 };
13706 
13707 /**
13708  * @protected
13709  * @static
13710  * @param {number} year
13711  * @param {number=} cycle
13712  * @return {number}
13713  */
13714 ilib.Cal.Han._getElapsedYear = function(year, cycle) {
13715 	var elapsedYear = year || 0;
13716 	if (typeof(year) !== 'undefined' && year < 61 && typeof(cycle) !== 'undefined') {
13717 		elapsedYear = 60 * cycle + year;
13718 	}
13719 	return elapsedYear;
13720 };
13721 
13722 /**
13723  * @protected
13724  * @static
13725  * @param {number} jd julian day to calculate from
13726  * @param {number} longitude longitude to seek 
13727  * @returns {number} the julian day of the next time that the solar longitude 
13728  * is a multiple of the given longitude
13729  */
13730 ilib.Cal.Han._hanNextSolarLongitude = function(jd, longitude) {
13731 	var tz = ilib.Cal.Han._chineseTZ(jd);
13732 	var uni = ilib.Date._universalFromLocal(jd, tz);
13733 	var sol = ilib.Date._nextSolarLongitude(uni, longitude);
13734 	return ilib.Date._localFromUniversal(sol, tz);
13735 };
13736 
13737 /**
13738  * @protected
13739  * @static
13740  * @param {number} jd julian day to calculate from 
13741  * @returns {number} the major solar term for the julian day
13742  */
13743 ilib.Cal.Han._majorSTOnOrAfter = function(jd) {
13744 	var tz = ilib.Cal.Han._chineseTZ(jd);
13745 	var uni = ilib.Date._universalFromLocal(jd, tz);
13746 	var next = ilib.Date._fixangle(30 * Math.ceil(ilib.Date._solarLongitude(uni)/30));
13747 	return ilib.Cal.Han._hanNextSolarLongitude(jd, next);
13748 };
13749 
13750 /**
13751  * @protected
13752  * @static
13753  * @param {number} year the year for which the leap year information is being sought
13754  * @param {number=} cycle if the given year < 60, this can specify the cycle. If the
13755  * cycle is not given, then the year should be given as elapsed years since the beginning
13756  * of the epoch
13757  */
13758 ilib.Cal.Han._solsticeBefore = function (year, cycle) {
13759 	var elapsedYear = ilib.Cal.Han._getElapsedYear(year, cycle);
13760 	var gregyear = elapsedYear - 2697;
13761 	var rd = new ilib.Date.GregRataDie({
13762 		year: gregyear-1, 
13763 		month: 12, 
13764 		day: 15, 
13765 		hour: 0, 
13766 		minute: 0, 
13767 		second: 0, 
13768 		millisecond: 0
13769 	});
13770 	return ilib.Cal.Han._majorSTOnOrAfter(rd.getRataDie() + ilib.Date.RataDie.gregorianEpoch);
13771 };
13772 
13773 /**
13774  * @protected
13775  * @static
13776  * @param {number} jd julian day to calculate from
13777  * @returns {number} the current major solar term
13778  */
13779 ilib.Cal.Han._chineseTZ = function(jd) {
13780 	var year = ilib.Date.GregDate._calcYear(jd - ilib.Date.RataDie.gregorianEpoch);
13781 	return year < 1929 ? 465.6666666666666666 : 480;
13782 };
13783 
13784 /**
13785  * @protected
13786  * @static
13787  * @param {number} jd julian day to calculate from 
13788  * @returns {number} the julian day of next new moon on or after the given julian day date
13789  */
13790 ilib.Cal.Han._newMoonOnOrAfter = function(jd) {
13791 	var tz = ilib.Cal.Han._chineseTZ(jd);
13792 	var uni = ilib.Date._universalFromLocal(jd, tz);
13793 	var moon = ilib.Date._newMoonAtOrAfter(uni);
13794 	// floor to the start of the julian day
13795 	return ilib.Date._floorToJD(ilib.Date._localFromUniversal(moon, tz)); 
13796 };
13797 
13798 /**
13799  * @protected
13800  * @static
13801  * @param {number} jd julian day to calculate from 
13802  * @returns {number} the julian day of previous new moon before the given julian day date
13803  */
13804 ilib.Cal.Han._newMoonBefore = function(jd) {
13805 	var tz = ilib.Cal.Han._chineseTZ(jd);
13806 	var uni = ilib.Date._universalFromLocal(jd, tz);
13807 	var moon = ilib.Date._newMoonBefore(uni);
13808 	// floor to the start of the julian day
13809 	return ilib.Date._floorToJD(ilib.Date._localFromUniversal(moon, tz));
13810 };
13811 
13812 /**
13813  * @static
13814  * @protected
13815  * @param {number} year the year for which the leap year information is being sought
13816  * @param {number=} cycle if the given year < 60, this can specify the cycle. If the
13817  * cycle is not given, then the year should be given as elapsed years since the beginning
13818  * of the epoch
13819  */
13820 ilib.Cal.Han._leapYearCalc = function(year, cycle) {
13821 	var ret = {
13822 		elapsedYear: ilib.Cal.Han._getElapsedYear(year, cycle)
13823 	};
13824 	ret.solstice1 = ilib.Cal.Han._solsticeBefore(ret.elapsedYear);
13825 	ret.solstice2 = ilib.Cal.Han._solsticeBefore(ret.elapsedYear+1);
13826 	// ceil to the end of the julian day
13827 	ret.m1 = ilib.Cal.Han._newMoonOnOrAfter(ilib.Date._ceilToJD(ret.solstice1));
13828 	ret.m2 = ilib.Cal.Han._newMoonBefore(ilib.Date._ceilToJD(ret.solstice2));
13829 	
13830 	return ret;
13831 };
13832 
13833 /**
13834  * @protected
13835  * @static
13836  * @param {number} jd julian day to calculate from
13837  * @returns {number} the current major solar term
13838  */
13839 ilib.Cal.Han._currentMajorST = function(jd) {
13840 	var s = ilib.Date._solarLongitude(ilib.Date._universalFromLocal(jd, ilib.Cal.Han._chineseTZ(jd)));
13841 	return ilib.amod(2 + Math.floor(s/30), 12);
13842 };
13843 
13844 /**
13845  * @protected
13846  * @static
13847  * @param {number} jd julian day to calculate from
13848  * @returns {boolean} true if there is no major solar term in the same year
13849  */
13850 ilib.Cal.Han._noMajorST = function(jd) {
13851 	return ilib.Cal.Han._currentMajorST(jd) === ilib.Cal.Han._currentMajorST(ilib.Cal.Han._newMoonOnOrAfter(jd+1));
13852 };
13853 
13854 /**
13855  * Return the number of months in the given year. The number of months in a year varies
13856  * for some luni-solar calendars because in some years, an extra month is needed to extend the 
13857  * days in a year to an entire solar year. The month is represented as a 1-based number
13858  * where 1=first month, 2=second month, etc.
13859  * 
13860  * @param {number} year a year for which the number of months is sought
13861  * @param {number=} cycle if the given year < 60, this can specify the cycle. If the
13862  * cycle is not given, then the year should be given as elapsed years since the beginning
13863  * of the epoch
13864  * @return {number} The number of months in the given year
13865  */
13866 ilib.Cal.Han.prototype.getNumMonths = function(year, cycle) {
13867 	return this.isLeapYear(year, cycle) ? 13 : 12;
13868 };
13869 
13870 /**
13871  * Return the number of days in a particular month in a particular year. This function
13872  * can return a different number for a month depending on the year because of things
13873  * like leap years.
13874  * 
13875  * @param {number} month the elapsed month for which the length is sought
13876  * @param {number} year the elapsed year within which that month can be found
13877  * @return {number} the number of days within the given month in the given year
13878  */
13879 ilib.Cal.Han.prototype.getMonLength = function(month, year) {
13880 	// distance between two new moons in Nanjing China
13881 	var calc = ilib.Cal.Han._leapYearCalc(year);
13882 	var priorNewMoon = ilib.Cal.Han._newMoonOnOrAfter(calc.m1 + month * 29);
13883 	var postNewMoon = ilib.Cal.Han._newMoonOnOrAfter(priorNewMoon + 1);
13884 	return postNewMoon - priorNewMoon;
13885 };
13886 
13887 /**
13888  * Return the equivalent year in the 2820 year cycle that begins on 
13889  * Far 1, 474. This particular cycle obeys the cycle-of-years formula 
13890  * whereas the others do not specifically. This cycle can be used as
13891  * a proxy for other years outside of the cycle by shifting them into 
13892  * the cycle.   
13893  * @param {number} year year to find the equivalent cycle year for
13894  * @returns {number} the equivalent cycle year
13895  */
13896 ilib.Cal.Han.prototype.equivalentCycleYear = function(year) {
13897 	var y = year - (year >= 0 ? 474 : 473);
13898 	return ilib.mod(y, 2820) + 474;
13899 };
13900 
13901 /**
13902  * Return true if the given year is a leap year in the Han calendar.
13903  * If the year is given as a year/cycle combination, then the year should be in the 
13904  * range [1,60] and the given cycle is the cycle in which the year is located. If 
13905  * the year is greater than 60, then
13906  * it represents the total number of years elapsed in the proleptic calendar since
13907  * the beginning of the Chinese epoch in on 15 Feb, -2636 (Gregorian). In this 
13908  * case, the cycle parameter is ignored.
13909  * 
13910  * @param {number} year the year for which the leap year information is being sought
13911  * @param {number=} cycle if the given year < 60, this can specify the cycle. If the
13912  * cycle is not given, then the year should be given as elapsed years since the beginning
13913  * of the epoch
13914  * @return {boolean} true if the given year is a leap year
13915  */
13916 ilib.Cal.Han.prototype.isLeapYear = function(year, cycle) {
13917 	var calc = ilib.Cal.Han._leapYearCalc(year, cycle);
13918 	return Math.round((calc.m2 - calc.m1) / 29.530588853000001) === 12;
13919 };
13920 
13921 /**
13922  * Return the month of the year that is the leap month. If the given year is
13923  * not a leap year, then this method will return -1.
13924  * 
13925  * @param {number} year the year for which the leap year information is being sought
13926  * @param {number=} cycle if the given year < 60, this can specify the cycle. If the
13927  * cycle is not given, then the year should be given as elapsed years since the beginning
13928  * of the epoch
13929  * @return {number} the number of the month that is doubled in this leap year, or -1
13930  * if this is not a leap year
13931  */
13932 ilib.Cal.Han.prototype.getLeapMonth = function(year, cycle) {
13933 	var calc = ilib.Cal.Han._leapYearCalc(year, cycle);
13934 	
13935 	if (Math.round((calc.m2 - calc.m1) / 29.530588853000001) != 12) {
13936 		return -1; // no leap month
13937 	}
13938 	
13939 	// search between rd1 and rd2 for the first month with no major solar term. That is our leap month.
13940 	var month = 0;
13941 	var m = ilib.Cal.Han._newMoonOnOrAfter(calc.m1+1);
13942 	while (!ilib.Cal.Han._noMajorST(m)) {
13943 		month++;
13944 		m = ilib.Cal.Han._newMoonOnOrAfter(m+1);
13945 	}
13946 	
13947 	// return the number of the month that is doubled
13948 	return month; 
13949 };
13950 
13951 /**
13952  * Return the date of Chinese New Years in the given calendar year.
13953  * 
13954  * @param {number} year the Chinese year for which the new year information is being sought
13955  * @param {number=} cycle if the given year < 60, this can specify the cycle. If the
13956  * cycle is not given, then the year should be given as elapsed years since the beginning
13957  * of the epoch
13958  * @return {number} the julian day of the beginning of the given year 
13959  */
13960 ilib.Cal.Han.prototype.newYears = function(year, cycle) {
13961 	var calc = ilib.Cal.Han._leapYearCalc(year, cycle);
13962 	var m2 = ilib.Cal.Han._newMoonOnOrAfter(calc.m1+1);
13963 	if (Math.round((calc.m2 - calc.m1) / 29.530588853000001) === 12 &&
13964 			(ilib.Cal.Han._noMajorST(calc.m1) || ilib.Cal.Han._noMajorST(m2)) ) {
13965 		return ilib.Cal.Han._newMoonOnOrAfter(m2+1);
13966 	}
13967 	return m2;
13968 };
13969 
13970 /**
13971  * Return the type of this calendar.
13972  * 
13973  * @return {string} the name of the type of this calendar 
13974  */
13975 ilib.Cal.Han.prototype.getType = function() {
13976 	return this.type;
13977 };
13978 
13979 /**
13980  * Return a date instance for this calendar type using the given
13981  * options.
13982  * @param {Object} options options controlling the construction of 
13983  * the date instance
13984  * @return {ilib.Date} a date appropriate for this calendar type
13985  */
13986 ilib.Cal.Han.prototype.newDateInstance = function (options) {
13987 	return new ilib.Date.HanDate(options);
13988 };
13989 
13990 /* register this calendar for the factory method */
13991 ilib.Cal._constructors["han"] = ilib.Cal.Han;
13992 
13993 /*
13994  * handate.js - Represent a date in the Han algorithmic calendar
13995  * 
13996  * Copyright © 2014, JEDLSoft
13997  *
13998  * Licensed under the Apache License, Version 2.0 (the "License");
13999  * you may not use this file except in compliance with the License.
14000  * You may obtain a copy of the License at
14001  *
14002  *     http://www.apache.org/licenses/LICENSE-2.0
14003  *
14004  * Unless required by applicable law or agreed to in writing, software
14005  * distributed under the License is distributed on an "AS IS" BASIS,
14006  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14007  *
14008  * See the License for the specific language governing permissions and
14009  * limitations under the License.
14010  */
14011 
14012 /* !depends 
14013 date.js
14014 calendar/gregratadie.js 
14015 calendar/gregoriandate.js 
14016 calendar/han.js
14017 calendar/astro.js 
14018 util/utils.js
14019 util/search.js
14020 util/math.js
14021 localeinfo.js 
14022 julianday.js 
14023 */
14024 
14025 /**
14026  * Construct a new Han RD date number object. The constructor parameters can 
14027  * contain any of the following properties:
14028  * 
14029  * <ul>
14030  * <li><i>unixtime<i> - sets the time of this instance according to the given 
14031  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970, Gregorian
14032  * 
14033  * <li><i>julianday</i> - sets the time of this instance according to the given
14034  * Julian Day instance or the Julian Day given as a float
14035  * 
14036  * <li><i>cycle</i> - any integer giving the number of 60-year cycle in which the date is located.
14037  * If the cycle is not given but the year is, it is assumed that the year parameter is a fictitious 
14038  * linear count of years since the beginning of the epoch, much like other calendars. This linear
14039  * count is never used. If both the cycle and year are given, the year is wrapped to the range 0 
14040  * to 60 and treated as if it were a year in the regular 60-year cycle.
14041  * 
14042  * <li><i>year</i> - any integer, including 0
14043  * 
14044  * <li><i>month</i> - 1 to 12, where 1 means Farvardin, 2 means Ordibehesht, etc.
14045  * 
14046  * <li><i>day</i> - 1 to 31
14047  * 
14048  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
14049  * is always done with an unambiguous 24 hour representation
14050  * 
14051  * <li><i>minute</i> - 0 to 59
14052  * 
14053  * <li><i>second</i> - 0 to 59
14054  * 
14055  * <li><i>millisecond</i> - 0 to 999
14056  * 
14057  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
14058  * </ul>
14059  *
14060  * If the constructor is called with another Han date instance instead of
14061  * a parameter block, the other instance acts as a parameter block and its
14062  * settings are copied into the current instance.<p>
14063  * 
14064  * If the constructor is called with no arguments at all or if none of the 
14065  * properties listed above are present, then the RD is calculate based on 
14066  * the current date at the time of instantiation. <p>
14067  * 
14068  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
14069  * specified in the params, it is assumed that they have the smallest possible
14070  * value in the range for the property (zero or one).<p>
14071  * 
14072  * Depends directive: !depends handate.js
14073  * 
14074  * @private
14075  * @class
14076  * @constructor
14077  * @extends ilib.Date.RataDie
14078  * @param {Object=} params parameters that govern the settings and behaviour of this Han RD date
14079  */
14080 ilib.Date.HanRataDie = function(params) {
14081 	this.rd = undefined;
14082 	if (params && params.cal) {
14083 		this.cal = params.cal;
14084 		ilib.Date.RataDie.call(this, params);
14085 		if (params && typeof(params.callback) === 'function') {
14086 			params.callback(this);
14087 		}
14088 	} else {
14089 		new ilib.Cal.Han({
14090 			sync: params && params.sync,
14091 			loadParams: params && params.loadParams,
14092 			callback: ilib.bind(this, function(c) {
14093 				this.cal = c;
14094 				ilib.Date.RataDie.call(this, params);
14095 				if (params && typeof(params.callback) === 'function') {
14096 					params.callback(this);
14097 				}
14098 			})
14099 		});
14100 	}
14101 };
14102 
14103 ilib.Date.HanRataDie.prototype = new ilib.Date.RataDie();
14104 ilib.Date.HanRataDie.prototype.parent = ilib.Date.RataDie;
14105 ilib.Date.HanRataDie.prototype.constructor = ilib.Date.HanRataDie;
14106 
14107 /**
14108  * The difference between a zero Julian day and the first Han date
14109  * which is February 15, -2636 (Gregorian).
14110  * @private
14111  * @const
14112  * @type number
14113  */
14114 ilib.Date.HanRataDie.epoch = 758325.5;
14115 
14116 /**
14117  * Calculate the Rata Die (fixed day) number of the given date from the
14118  * date components.
14119  *
14120  * @protected
14121  * @param {Object} date the date components to calculate the RD from
14122  */
14123 ilib.Date.HanRataDie.prototype._setDateComponents = function(date) {
14124 	var calc = ilib.Cal.Han._leapYearCalc(date.year, date.cycle);
14125 	var m2 = ilib.Cal.Han._newMoonOnOrAfter(calc.m1+1);
14126 	var newYears;
14127 	this.leapYear = (Math.round((calc.m2 - calc.m1) / 29.530588853000001) === 12);
14128 	if (this.leapYear && (ilib.Cal.Han._noMajorST(calc.m1) || ilib.Cal.Han._noMajorST(m2)) ) {
14129 		newYears = ilib.Cal.Han._newMoonOnOrAfter(m2+1);
14130 	} else {
14131 		newYears = m2;
14132 	}
14133 
14134 	var priorNewMoon = ilib.Cal.Han._newMoonOnOrAfter(calc.m1 + date.month * 29); // this is a julian day
14135 	this.priorLeapMonth = ilib.Date.HanDate._priorLeapMonth(newYears, ilib.Cal.Han._newMoonBefore(priorNewMoon));
14136 	this.leapMonth = (this.leapYear && ilib.Cal.Han._noMajorST(priorNewMoon) && !this.priorLeapMonth);
14137 
14138 	var rdtime = (date.hour * 3600000 +
14139 		date.minute * 60000 +
14140 		date.second * 1000 +
14141 		date.millisecond) /
14142 		86400000;
14143 	
14144 	/*
14145 	console.log("getRataDie: converting " +  JSON.stringify(date) + " to an RD");
14146 	console.log("getRataDie: year is " +  date.year + " plus cycle " + date.cycle);
14147 	console.log("getRataDie: isLeapYear is " +  this.leapYear);
14148 	console.log("getRataDie: priorNewMoon is " +  priorNewMoon);
14149 	console.log("getRataDie: day in month is " +  date.day);
14150 	console.log("getRataDie: rdtime is " +  rdtime);
14151 	console.log("getRataDie: rd is " +  (priorNewMoon + date.day - 1 + rdtime));
14152 	*/
14153 	
14154 	this.rd = priorNewMoon + date.day - 1 + rdtime - ilib.Date.RataDie.gregorianEpoch;
14155 };
14156 
14157 /**
14158  * Return the rd number of the particular day of the week on or before the 
14159  * given rd. eg. The Sunday on or before the given rd.
14160  * @private
14161  * @param {number} rd the rata die date of the reference date
14162  * @param {number} dayOfWeek the day of the week that is being sought relative 
14163  * to the current date
14164  * @return {number} the rd of the day of the week
14165  */
14166 ilib.Date.HanRataDie.prototype._onOrBefore = function(rd, dayOfWeek) {
14167 	return rd - ilib.mod(Math.floor(rd) - dayOfWeek, 7);
14168 };
14169 
14170 /**
14171  * @class
14172  * 
14173  * Construct a new Han date object. The constructor parameters can 
14174  * contain any of the following properties:
14175  * 
14176  * <ul>
14177  * <li><i>unixtime<i> - sets the time of this instance according to the given 
14178  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970, Gregorian
14179  * 
14180  * <li><i>julianday</i> - sets the time of this instance according to the given
14181  * Julian Day instance or the Julian Day given as a float
14182  * 
14183  * <li><i>cycle</i> - any integer giving the number of 60-year cycle in which the date is located.
14184  * If the cycle is not given but the year is, it is assumed that the year parameter is a fictitious 
14185  * linear count of years since the beginning of the epoch, much like other calendars. This linear
14186  * count is never used. If both the cycle and year are given, the year is wrapped to the range 0 
14187  * to 60 and treated as if it were a year in the regular 60-year cycle.
14188  * 
14189  * <li><i>year</i> - any integer, including 0
14190  * 
14191  * <li><i>month</i> - 1 to 12, where 1 means Farvardin, 2 means Ordibehesht, etc.
14192  * 
14193  * <li><i>day</i> - 1 to 31
14194  * 
14195  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
14196  * is always done with an unambiguous 24 hour representation
14197  * 
14198  * <li><i>minute</i> - 0 to 59
14199  * 
14200  * <li><i>second</i> - 0 to 59
14201  * 
14202  * <li><i>millisecond</i> - 0 to 999
14203  * 
14204  * <li><i>timezone</i> - the ilib.TimeZone instance or time zone name as a string 
14205  * of this han date. The date/time is kept in the local time. The time zone
14206  * is used later if this date is formatted according to a different time zone and
14207  * the difference has to be calculated, or when the date format has a time zone
14208  * component in it.
14209  * 
14210  * <li><i>locale</i> - locale for this han date. If the time zone is not 
14211  * given, it can be inferred from this locale. For locales that span multiple
14212  * time zones, the one with the largest population is chosen as the one that 
14213  * represents the locale.
14214  * 
14215  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
14216  * </ul>
14217  *
14218  * If the constructor is called with another Han date instance instead of
14219  * a parameter block, the other instance acts as a parameter block and its
14220  * settings are copied into the current instance.<p>
14221  * 
14222  * If the constructor is called with no arguments at all or if none of the 
14223  * properties listed above 
14224  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
14225  * components are 
14226  * filled in with the current date at the time of instantiation. Note that if
14227  * you do not give the time zone when defaulting to the current time and the 
14228  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
14229  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
14230  * Mean Time").<p>
14231  * 
14232  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
14233  * specified in the params, it is assumed that they have the smallest possible
14234  * value in the range for the property (zero or one).<p>
14235  * 
14236  * Depends directive: !depends handate.js
14237  * 
14238  * @constructor
14239  * @extends ilib.Date
14240  * @param {Object=} params parameters that govern the settings and behaviour of this Han date
14241  */
14242 ilib.Date.HanDate = function(params) {
14243 	this.timezone = "local";
14244 	if (params) {
14245 		if (params.locale) {
14246 			this.locale = (typeof(params.locale) === 'string') ? new ilib.Locale(params.locale) : params.locale;
14247 			var li = new ilib.LocaleInfo(this.locale);
14248 			this.timezone = li.getTimeZone(); 
14249 		}
14250 		if (params.timezone) {
14251 			this.timezone = params.timezone;
14252 		}
14253 	}
14254 	
14255 	new ilib.Cal.Han({
14256 		sync: params && typeof(params) === 'boolean' ? params.sync : true,
14257 		loadParams: params && params.loadParams,
14258 		callback: ilib.bind(this, function (cal) {
14259 			this.cal = cal;
14260 	
14261 			if (params && (params.year || params.month || params.day || params.hour ||
14262 				params.minute || params.second || params.millisecond || params.cycle || params.cycleYear)) {
14263 				if (typeof(params.cycle) !== 'undefined') {
14264 					/**
14265 					 * Cycle number in the Han calendar.
14266 					 * @type number
14267 					 */
14268 					this.cycle = parseInt(params.cycle, 10) || 0;
14269 					
14270 					var year = (typeof(params.year) !== 'undefined' ? parseInt(params.year, 10) : parseInt(params.cycleYear, 10)) || 0;
14271 					
14272 					/**
14273 					 * Year in the Han calendar.
14274 					 * @type number
14275 					 */
14276 					this.year = ilib.Cal.Han._getElapsedYear(year, this.cycle);
14277 				} else {
14278 					if (typeof(params.year) !== 'undefined') {
14279 						this.year = parseInt(params.year, 10) || 0;
14280 						this.cycle = Math.floor((this.year - 1) / 60);
14281 					} else {
14282 						this.year = this.cycle = 0;
14283 					}
14284 				}	
14285 				
14286 				/**
14287 				 * The month number, ranging from 1 to 13
14288 				 * @type number
14289 				 */
14290 				this.month = parseInt(params.month, 10) || 1;
14291 	
14292 				/**
14293 				 * The day of the month. This ranges from 1 to 30.
14294 				 * @type number
14295 				 */
14296 				this.day = parseInt(params.day, 10) || 1;
14297 				
14298 				/**
14299 				 * The hour of the day. This can be a number from 0 to 23, as times are
14300 				 * stored unambiguously in the 24-hour clock.
14301 				 * @type number
14302 				 */
14303 				this.hour = parseInt(params.hour, 10) || 0;
14304 	
14305 				/**
14306 				 * The minute of the hours. Ranges from 0 to 59.
14307 				 * @type number
14308 				 */
14309 				this.minute = parseInt(params.minute, 10) || 0;
14310 	
14311 				/**
14312 				 * The second of the minute. Ranges from 0 to 59.
14313 				 * @type number
14314 				 */
14315 				this.second = parseInt(params.second, 10) || 0;
14316 	
14317 				/**
14318 				 * The millisecond of the second. Ranges from 0 to 999.
14319 				 * @type number
14320 				 */
14321 				this.millisecond = parseInt(params.millisecond, 10) || 0;
14322 			
14323 				// derived properties
14324 				
14325 				/**
14326 				 * Year in the cycle of the Han calendar
14327 				 * @type number
14328 				 */
14329 				this.cycleYear = ilib.amod(this.year, 60); 
14330 
14331 				/**
14332 				 * The day of the year. Ranges from 1 to 384.
14333 				 * @type number
14334 				 */
14335 				this.dayOfYear = parseInt(params.dayOfYear, 10);
14336 	
14337 				if (typeof(params.dst) === 'boolean') {
14338 					this.dst = params.dst;
14339 				}
14340 				
14341 				this.newRd({
14342 					cal: this.cal,
14343 					cycle: this.cycle,
14344 					year: this.year,
14345 					month: this.month,
14346 					day: this.day,
14347 					hour: this.hour,
14348 					minute: this.minute,
14349 					second: this.second,
14350 					millisecond: this.millisecond,
14351 					sync: params && typeof(params.sync) === 'boolean' ? params.sync : true,
14352 					loadParams: params && params.loadParams,
14353 					callback: ilib.bind(this, function (rd) {
14354 						if (rd) {
14355 							this.rd = rd;
14356 							
14357 							// add the time zone offset to the rd to convert to UTC
14358 							if (!this.tz) {
14359 								this.tz = new ilib.TimeZone({id: this.timezone});
14360 							}
14361 							// getOffsetMillis requires that this.year, this.rd, and this.dst 
14362 							// are set in order to figure out which time zone rules apply and 
14363 							// what the offset is at that point in the year
14364 							this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
14365 							if (this.offset !== 0) {
14366 								this.rd = this.newRd({
14367 									cal: this.cal,
14368 									rd: this.rd.getRataDie() - this.offset
14369 								});
14370 								this._calcLeap();
14371 							} else {
14372 								// re-use the derived properties from the RD calculations
14373 								this.leapMonth = this.rd.leapMonth;
14374 								this.priorLeapMonth = this.rd.priorLeapMonth;
14375 								this.leapYear = this.rd.leapYear;
14376 							}
14377 						}
14378 						
14379 						if (!this.rd) {
14380 							this.rd = this.newRd(ilib.merge(params || {}, {
14381 								cal: this.cal
14382 							}));
14383 							this._calcDateComponents();
14384 						}
14385 						
14386 						if (params && typeof(params.onLoad) === 'function') {
14387 							params.onLoad(this);
14388 						}
14389 					})
14390 				});
14391 			} else {
14392 				if (!this.rd) {
14393 					this.rd = this.newRd(ilib.merge(params || {}, {
14394 						cal: this.cal
14395 					}));
14396 					this._calcDateComponents();
14397 				}
14398 				
14399 				if (params && typeof(params.onLoad) === 'function') {
14400 					params.onLoad(this);
14401 				}
14402 			}
14403 		})
14404 	});
14405 
14406 };
14407 
14408 ilib.Date.HanDate.prototype = new ilib.Date({noinstance: true});
14409 ilib.Date.HanDate.prototype.parent = ilib.Date;
14410 ilib.Date.HanDate.prototype.constructor = ilib.Date.HanDate;
14411 
14412 /**
14413  * Return a new RD for this date type using the given params.
14414  * @protected
14415  * @param {Object=} params the parameters used to create this rata die instance
14416  * @returns {ilib.Date.RataDie} the new RD instance for the given params
14417  */
14418 ilib.Date.HanDate.prototype.newRd = function (params) {
14419 	return new ilib.Date.HanRataDie(params);
14420 };
14421 
14422 /**
14423  * @protected
14424  * @static
14425  * @param {number} jd1 first julian day
14426  * @param {number} jd2 second julian day
14427  * @returns {boolean} true if there is a leap month earlier in the same year 
14428  * as the given months 
14429  */
14430 ilib.Date.HanDate._priorLeapMonth = function(jd1, jd2) {
14431 	return jd2 >= jd1 &&
14432 		(ilib.Date.HanDate._priorLeapMonth(jd1, ilib.Cal.Han._newMoonBefore(jd2)) ||
14433 				ilib.Cal.Han._noMajorST(jd2));
14434 };
14435 
14436 /**
14437  * Return the year for the given RD
14438  * @protected
14439  * @param {number} rd RD to calculate from 
14440  * @returns {number} the year for the RD
14441  */
14442 ilib.Date.HanDate.prototype._calcYear = function(rd) {
14443 	var gregdate = new ilib.Date.GregDate({
14444 		rd: rd,
14445 		timezone: this.timezone
14446 	});
14447 	var hanyear = gregdate.year + 2697;
14448 	var newYears = this.cal.newYears(hanyear);
14449 	return hanyear - ((rd + ilib.Date.RataDie.gregorianEpoch < newYears) ? 1 : 0);
14450 };
14451 
14452 /** 
14453  * @private 
14454  * Calculate the leap year and months from the RD.
14455  */
14456 ilib.Date.HanDate.prototype._calcLeap = function() {
14457 	var jd = this.rd.getRataDie() + ilib.Date.RataDie.gregorianEpoch;
14458 	
14459 	var calc = ilib.Cal.Han._leapYearCalc(this.year);
14460 	var m2 = ilib.Cal.Han._newMoonOnOrAfter(calc.m1+1);
14461 	this.leapYear = Math.round((calc.m2 - calc.m1) / 29.530588853000001) === 12;
14462 	
14463 	var newYears = (this.leapYear &&
14464 		(ilib.Cal.Han._noMajorST(calc.m1) || ilib.Cal.Han._noMajorST(m2))) ?
14465 				ilib.Cal.Han._newMoonOnOrAfter(m2+1) : m2;
14466 	
14467 	var m = ilib.Cal.Han._newMoonBefore(jd + 1);
14468 	this.priorLeapMonth = ilib.Date.HanDate._priorLeapMonth(newYears, ilib.Cal.Han._newMoonBefore(m));
14469 	this.leapMonth = (this.leapYear && ilib.Cal.Han._noMajorST(m) && !this.priorLeapMonth);
14470 };
14471 
14472 /**
14473  * @private
14474  * Calculate date components for the given RD date.
14475  */
14476 ilib.Date.HanDate.prototype._calcDateComponents = function () {
14477 	var remainder,
14478 		jd = this.rd.getRataDie() + ilib.Date.RataDie.gregorianEpoch;
14479 
14480 	// console.log("HanDate._calcDateComponents: calculating for jd " + jd);
14481 
14482 	if (typeof(this.offset) === "undefined") {
14483 		// now offset the jd by the time zone, then recalculate in case we were 
14484 		// near the year boundary
14485 		if (!this.tz) {
14486 			this.tz = new ilib.TimeZone({id: this.timezone});
14487 		}
14488 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
14489 	}
14490 	
14491 	if (this.offset !== 0) {
14492 		jd += this.offset;
14493 	}
14494 
14495 	// use the Gregorian calendar objects as a convenient way to short-cut some
14496 	// of the date calculations
14497 	
14498 	var gregyear = ilib.Date.GregDate._calcYear(this.rd.getRataDie());
14499 	this.year = gregyear + 2697;
14500 	var calc = ilib.Cal.Han._leapYearCalc(this.year);
14501 	var m2 = ilib.Cal.Han._newMoonOnOrAfter(calc.m1+1);
14502 	this.leapYear = Math.round((calc.m2 - calc.m1) / 29.530588853000001) === 12;
14503 	var newYears = (this.leapYear &&
14504 		(ilib.Cal.Han._noMajorST(calc.m1) || ilib.Cal.Han._noMajorST(m2))) ?
14505 				ilib.Cal.Han._newMoonOnOrAfter(m2+1) : m2;
14506 	
14507 	// See if it's between Jan 1 and the Chinese new years of that Gregorian year. If
14508 	// so, then the Han year is actually the previous one
14509 	if (jd < newYears) {
14510 		this.year--;
14511 		calc = ilib.Cal.Han._leapYearCalc(this.year);
14512 		m2 = ilib.Cal.Han._newMoonOnOrAfter(calc.m1+1);
14513 		this.leapYear = Math.round((calc.m2 - calc.m1) / 29.530588853000001) === 12;
14514 		newYears = (this.leapYear &&
14515 			(ilib.Cal.Han._noMajorST(calc.m1) || ilib.Cal.Han._noMajorST(m2))) ?
14516 					ilib.Cal.Han._newMoonOnOrAfter(m2+1) : m2;
14517 	}
14518 	// month is elapsed month, not the month number + leap month boolean
14519 	var m = ilib.Cal.Han._newMoonBefore(jd + 1);
14520 	this.month = Math.round((m - calc.m1) / 29.530588853000001);
14521 	
14522 	this.priorLeapMonth = ilib.Date.HanDate._priorLeapMonth(newYears, ilib.Cal.Han._newMoonBefore(m));
14523 	this.leapMonth = (this.leapYear && ilib.Cal.Han._noMajorST(m) && !this.priorLeapMonth);
14524 	
14525 	this.cycle = Math.floor((this.year - 1) / 60);
14526 	this.cycleYear = ilib.amod(this.year, 60);
14527 	this.day = ilib.Date._floorToJD(jd) - m + 1;
14528 
14529 	/*
14530 	console.log("HanDate._calcDateComponents: year is " + this.year);
14531 	console.log("HanDate._calcDateComponents: isLeapYear is " + this.leapYear);
14532 	console.log("HanDate._calcDateComponents: cycle is " + this.cycle);
14533 	console.log("HanDate._calcDateComponents: cycleYear is " + this.cycleYear);
14534 	console.log("HanDate._calcDateComponents: month is " + this.month);
14535 	console.log("HanDate._calcDateComponents: isLeapMonth is " + this.leapMonth);
14536 	console.log("HanDate._calcDateComponents: day is " + this.day);
14537 	*/
14538 
14539 	// floor to the start of the julian day
14540 	remainder = jd - ilib.Date._floorToJD(jd);
14541 	
14542 	// console.log("HanDate._calcDateComponents: time remainder is " + remainder);
14543 	
14544 	// now convert to milliseconds for the rest of the calculation
14545 	remainder = Math.round(remainder * 86400000);
14546 	
14547 	this.hour = Math.floor(remainder/3600000);
14548 	remainder -= this.hour * 3600000;
14549 	
14550 	this.minute = Math.floor(remainder/60000);
14551 	remainder -= this.minute * 60000;
14552 	
14553 	this.second = Math.floor(remainder/1000);
14554 	remainder -= this.second * 1000;
14555 	
14556 	this.millisecond = remainder;
14557 };
14558 
14559 /**
14560  * Return the year within the Chinese cycle of this date. Cycles are 60 
14561  * years long, and the value returned from this method is the number of the year 
14562  * within this cycle. The year returned from getYear() is the total elapsed 
14563  * years since the beginning of the Chinese epoch and does not include 
14564  * the cycles. 
14565  * 
14566  * @return {number} the year within the current Chinese cycle
14567  */
14568 ilib.Date.HanDate.prototype.getCycleYears = function() {
14569 	return this.cycleYear;
14570 };
14571 
14572 /**
14573  * Return the Chinese cycle number of this date. Cycles are 60 years long,
14574  * and the value returned from getCycleYear() is the number of the year 
14575  * within this cycle. The year returned from getYear() is the total elapsed 
14576  * years since the beginning of the Chinese epoch and does not include 
14577  * the cycles. 
14578  * 
14579  * @return {number} the current Chinese cycle
14580  */
14581 ilib.Date.HanDate.prototype.getCycles = function() {
14582 	return this.cycle;
14583 };
14584 
14585 /**
14586  * Return whether the year of this date is a leap year in the Chinese Han 
14587  * calendar. 
14588  * 
14589  * @return {boolean} true if the year of this date is a leap year in the 
14590  * Chinese Han calendar. 
14591  */
14592 ilib.Date.HanDate.prototype.isLeapYear = function() {
14593 	return this.leapYear;
14594 };
14595 
14596 /**
14597  * Return whether the month of this date is a leap month in the Chinese Han 
14598  * calendar.
14599  * 
14600  * @return {boolean} true if the month of this date is a leap month in the 
14601  * Chinese Han calendar.
14602  */
14603 ilib.Date.HanDate.prototype.isLeapMonth = function() {
14604 	return this.leapMonth;
14605 };
14606 
14607 /**
14608  * Return the day of the week of this date. The day of the week is encoded
14609  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
14610  * 
14611  * @return {number} the day of the week
14612  */
14613 ilib.Date.HanDate.prototype.getDayOfWeek = function() {
14614 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
14615 	return ilib.mod(rd, 7);
14616 };
14617 
14618 /**
14619  * Return the ordinal day of the year. Days are counted from 1 and proceed linearly up to 
14620  * 365, regardless of months or weeks, etc. That is, Farvardin 1st is day 1, and 
14621  * December 31st is 365 in regular years, or 366 in leap years.
14622  * @return {number} the ordinal day of the year
14623  */
14624 ilib.Date.HanDate.prototype.getDayOfYear = function() {
14625 	var newYears = this.cal.newYears(this.year);
14626 	var priorNewMoon = ilib.Cal.Han._newMoonOnOrAfter(newYears + (this.month -1) * 29);
14627 	return priorNewMoon - newYears + this.day;
14628 };
14629 
14630 /**
14631  * Return the era for this date as a number. The value for the era for Han 
14632  * calendars is -1 for "before the han era" (BP) and 1 for "the han era" (anno 
14633  * persico or AP). 
14634  * BP dates are any date before Farvardin 1, 1 AP. In the proleptic Han calendar, 
14635  * there is a year 0, so any years that are negative or zero are BP.
14636  * @return {number} 1 if this date is in the common era, -1 if it is before the 
14637  * common era 
14638  */
14639 ilib.Date.HanDate.prototype.getEra = function() {
14640 	return (this.year < 1) ? -1 : 1;
14641 };
14642 
14643 /**
14644  * Return the name of the calendar that governs this date.
14645  * 
14646  * @return {string} a string giving the name of the calendar
14647  */
14648 ilib.Date.HanDate.prototype.getCalendar = function() {
14649 	return "han";
14650 };
14651 
14652 // register with the factory method
14653 ilib.Date._constructors["han"] = ilib.Date.HanDate;
14654 /*
14655  * ethiopic.js - Represent a Ethiopic calendar object.
14656  * 
14657  * Copyright © 2015, JEDLSoft
14658  *
14659  * Licensed under the Apache License, Version 2.0 (the "License");
14660  * you may not use this file except in compliance with the License.
14661  * You may obtain a copy of the License at
14662  *
14663  *     http://www.apache.org/licenses/LICENSE-2.0
14664  *
14665  * Unless required by applicable law or agreed to in writing, software
14666  * distributed under the License is distributed on an "AS IS" BASIS,
14667  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14668  *
14669  * See the License for the specific language governing permissions and
14670  * limitations under the License.
14671  */
14672 
14673 
14674 /* !depends calendar.js locale.js date.js julianday.js util/utils.js util/math.js */
14675 
14676 /**
14677  * @class
14678  * Construct a new Ethiopic calendar object. This class encodes information about
14679  * a Ethiopic calendar.<p>
14680  * 
14681  * Depends directive: !depends ethiopic.js
14682  * 
14683  * @constructor
14684  * @implements ilib.Cal
14685  */
14686 ilib.Cal.Ethiopic = function() {
14687 	this.type = "ethiopic";
14688 };
14689 
14690 /**
14691  * Return the number of months in the given year. The number of months in a year varies
14692  * for lunar calendars because in some years, an extra month is needed to extend the 
14693  * days in a year to an entire solar year. The month is represented as a 1-based number
14694  * where 1=Maskaram, 2=Teqemt, etc. until 13=Paguemen.
14695  * 
14696  * @param {number} year a year for which the number of months is sought
14697  */
14698 ilib.Cal.Ethiopic.prototype.getNumMonths = function(year) {
14699 	return 13;
14700 };
14701 
14702 /**
14703  * Return the number of days in a particular month in a particular year. This function
14704  * can return a different number for a month depending on the year because of things
14705  * like leap years.
14706  * 
14707  * @param {number|string} month the month for which the length is sought
14708  * @param {number} year the year within which that month can be found
14709  * @return {number} the number of days within the given month in the given year
14710  */
14711 ilib.Cal.Ethiopic.prototype.getMonLength = function(month, year) {
14712 	var m = month;
14713 	switch (typeof(m)) {
14714         case "string": 
14715             m = parseInt(m, 10); 
14716             break;
14717         case "function":
14718         case "object":
14719         case "undefined":
14720             return 30;
14721             break;
14722     }    
14723 	if (m < 13) {
14724 		return 30;
14725 	} else {
14726 		return this.isLeapYear(year) ? 6 : 5;
14727 	}
14728 };
14729 
14730 /**
14731  * Return true if the given year is a leap year in the Ethiopic calendar.
14732  * The year parameter may be given as a number, or as a JulDate object.
14733  * @param {number|ilib.Date.JulDate|string} year the year for which the leap year information is being sought
14734  * @return {boolean} true if the given year is a leap year
14735  */
14736 ilib.Cal.Ethiopic.prototype.isLeapYear = function(year) {
14737 	var y = year;
14738 	 switch (typeof(y)) {
14739         case "string":
14740             y = parseInt(y, 10);
14741             break;
14742         case "object":
14743             if (typeof(y.year) !== "number") { // in case it is an ilib.Date object
14744                 return false;
14745             }
14746             y = y.year;
14747             break;
14748         case "function":
14749         case "undefined":
14750             return false;
14751             break;
14752     }
14753 	return ilib.mod(y, 4) === 3;
14754 };
14755 
14756 /**
14757  * Return the type of this calendar.
14758  * 
14759  * @return {string} the name of the type of this calendar 
14760  */
14761 ilib.Cal.Ethiopic.prototype.getType = function() {
14762 	return this.type;
14763 };
14764 
14765 /**
14766  * Return a date instance for this calendar type using the given
14767  * options.
14768  * @param {Object} options options controlling the construction of 
14769  * the date instance
14770  * @return {ilib.Date} a date appropriate for this calendar type
14771  */
14772 ilib.Cal.Ethiopic.prototype.newDateInstance = function (options) {
14773 	return new ilib.Date.EthiopicDate(options);
14774 };
14775 
14776 /* register this calendar for the factory method */
14777 ilib.Cal._constructors["ethiopic"] = ilib.Cal.Ethiopic;
14778 /*
14779  * ethiopicdate.js - Represent a date in the Ethiopic calendar
14780  * 
14781  * Copyright © 2015, JEDLSoft
14782  *
14783  * Licensed under the Apache License, Version 2.0 (the "License");
14784  * you may not use this file except in compliance with the License.
14785  * You may obtain a copy of the License at
14786  *
14787  *     http://www.apache.org/licenses/LICENSE-2.0
14788  *
14789  * Unless required by applicable law or agreed to in writing, software
14790  * distributed under the License is distributed on an "AS IS" BASIS,
14791  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14792  *
14793  * See the License for the specific language governing permissions and
14794  * limitations under the License.
14795  */
14796 
14797 /* !depends 
14798 date.js 
14799 calendar/ethiopic.js 
14800 util/utils.js
14801 util/search.js 
14802 util/math.js
14803 localeinfo.js 
14804 julianday.js 
14805 */
14806 
14807 /**
14808  * @class
14809  * Construct a new Ethiopic RD date number object. The constructor parameters can 
14810  * contain any of the following properties:
14811  * 
14812  * <ul>
14813  * <li><i>unixtime<i> - sets the time of this instance according to the given 
14814  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
14815  * 
14816  * <li><i>julianday</i> - sets the time of this instance according to the given
14817  * Julian Day instance or the Julian Day given as a float
14818  * 
14819  * <li><i>year</i> - any integer, including 0
14820  * 
14821  * <li><i>month</i> - 1 to 12, where 1 means Maskaram, 2 means Teqemt, etc., and 13 means Paguemen
14822  * 
14823  * <li><i>day</i> - 1 to 30
14824  * 
14825  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
14826  * is always done with an unambiguous 24 hour representation
14827  * 
14828  * <li><i>minute</i> - 0 to 59
14829  * 
14830  * <li><i>second</i> - 0 to 59
14831  * 
14832  * <li><i>millisecond</i> - 0 to 999
14833  * 
14834  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
14835  * </ul>
14836  *
14837  * If the constructor is called with another Ethiopic date instance instead of
14838  * a parameter block, the other instance acts as a parameter block and its
14839  * settings are copied into the current instance.<p>
14840  * 
14841  * If the constructor is called with no arguments at all or if none of the 
14842  * properties listed above are present, then the RD is calculate based on 
14843  * the current date at the time of instantiation. <p>
14844  * 
14845  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
14846  * specified in the params, it is assumed that they have the smallest possible
14847  * value in the range for the property (zero or one).<p>
14848  * 
14849  * Depends directive: !depends ethiopicdate.js
14850  * 
14851  * @private
14852  * @constructor
14853  * @extends ilib.Date.RataDie
14854  * @param {Object=} params parameters that govern the settings and behaviour of this Ethiopic RD date
14855  */
14856 ilib.Date.EthiopicRataDie = function(params) {
14857 	this.cal = params && params.cal || new ilib.Cal.Ethiopic();
14858 	this.rd = undefined;
14859 	ilib.Date.RataDie.call(this, params);
14860 };
14861 
14862 ilib.Date.EthiopicRataDie.prototype = new ilib.Date.RataDie();
14863 ilib.Date.EthiopicRataDie.prototype.parent = ilib.Date.RataDie;
14864 ilib.Date.EthiopicRataDie.prototype.constructor = ilib.Date.EthiopicRataDie;
14865 
14866 /**
14867  * The difference between the zero Julian day and the first Ethiopic date
14868  * of Friday, August 29, 8 CE Julian at 6:00am UTC.<p> 
14869  * 
14870  * See <a href="http://us.wow.com/wiki/Time_in_Ethiopia?s_chn=90&s_pt=aolsem&v_t=aolsem"
14871  * Time in Ethiopia</a> for information about how time is handled in Ethiopia.
14872  * 
14873  * @protected
14874  * @type number
14875  */
14876 ilib.Date.EthiopicRataDie.prototype.epoch = 1724219.75;
14877 
14878 /**
14879  * Calculate the Rata Die (fixed day) number of the given date from the
14880  * date components.
14881  * 
14882  * @protected
14883  * @param {Object} date the date components to calculate the RD from
14884  */
14885 ilib.Date.EthiopicRataDie.prototype._setDateComponents = function(date) {
14886 	var year = date.year;
14887 	var years = 365 * (year - 1) + Math.floor(year/4);
14888 	var dayInYear = (date.month-1) * 30 + date.day;
14889 	var rdtime = (date.hour * 3600000 +
14890 		date.minute * 60000 +
14891 		date.second * 1000 +
14892 		date.millisecond) / 
14893 		86400000;
14894 	
14895 	/*
14896 	console.log("calcRataDie: converting " +  JSON.stringify(parts));
14897 	console.log("getRataDie: year is " +  years);
14898 	console.log("getRataDie: day in year is " +  dayInYear);
14899 	console.log("getRataDie: rdtime is " +  rdtime);
14900 	console.log("getRataDie: rd is " +  (years + dayInYear + rdtime));
14901 	*/
14902 	
14903 	this.rd = years + dayInYear + rdtime;
14904 };
14905 
14906 /**
14907  * @class
14908  * Construct a new date object for the Ethiopic Calendar. The constructor can be called
14909  * with a parameter object that contains any of the following properties:
14910  * 
14911  * <ul>
14912  * <li><i>unixtime<i> - sets the time of this instance according to the given 
14913  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970 (Gregorian).
14914  * <li><i>julianday</i> - the Julian Day to set into this date
14915  * <li><i>year</i> - any integer
14916  * <li><i>month</i> - 1 to 13, where 1 means Maskaram, 2 means Teqemt, etc., and 13 means Paguemen
14917  * <li><i>day</i> - 1 to 30
14918  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
14919  * is always done with an unambiguous 24 hour representation
14920  * <li><i>minute</i> - 0 to 59
14921  * <li><i>second</i> - 0 to 59
14922  * <li><i>millisecond<i> - 0 to 999
14923  * <li><i>locale</i> - the ilib.TimeZone instance or time zone name as a string 
14924  * of this ethiopic date. The date/time is kept in the local time. The time zone
14925  * is used later if this date is formatted according to a different time zone and
14926  * the difference has to be calculated, or when the date format has a time zone
14927  * component in it.
14928  * <li><i>timezone</i> - the time zone of this instance. If the time zone is not 
14929  * given, it can be inferred from this locale. For locales that span multiple
14930  * time zones, the one with the largest population is chosen as the one that 
14931  * represents the locale. 
14932  * 
14933  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
14934  * </ul>
14935  *  
14936  * If called with another Ethiopic date argument, the date components of the given
14937  * date are copied into the current one.<p>
14938  * 
14939  * If the constructor is called with no arguments at all or if none of the 
14940  * properties listed above 
14941  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
14942  * components are 
14943  * filled in with the current date at the time of instantiation. Note that if
14944  * you do not give the time zone when defaulting to the current time and the 
14945  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
14946  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
14947  * Mean Time").<p>
14948  * 
14949  * Depends directive: !depends ethiopicdate.js
14950  * 
14951  * @constructor
14952  * @extends ilib.Date
14953  * @param {Object=} params parameters that govern the settings and behaviour of this Ethiopic date
14954  */
14955 ilib.Date.EthiopicDate = function(params) {
14956 	this.cal = new ilib.Cal.Ethiopic();
14957 	
14958 	if (params) {
14959 		if (typeof(params.noinstance) === 'boolean' && params.noinstance) {
14960 			// for doing inheritance, so don't need to fill in the data. The inheriting class only wants the methods.
14961 			return;
14962 		}
14963 		if (params.locale) {
14964 			this.locale = (typeof(params.locale) === 'string') ? new ilib.Locale(params.locale) : params.locale;
14965 			var li = new ilib.LocaleInfo(this.locale);
14966 			this.timezone = li.getTimeZone(); 
14967 		}
14968 		if (params.timezone) {
14969 			this.timezone = params.timezone;
14970 		}
14971 		
14972 		if (params.year || params.month || params.day || params.hour ||
14973 				params.minute || params.second || params.millisecond ) {
14974 			/**
14975 			 * Year in the Ethiopic calendar.
14976 			 * @type number
14977 			 */
14978 			this.year = parseInt(params.year, 10) || 0;
14979 			/**
14980 			 * The month number, ranging from 1 (Maskaram) to 13 (Paguemen).
14981 			 * @type number
14982 			 */
14983 			this.month = parseInt(params.month, 10) || 1;
14984 			/**
14985 			 * The day of the month. This ranges from 1 to 30.
14986 			 * @type number
14987 			 */
14988 			this.day = parseInt(params.day, 10) || 1;
14989 			/**
14990 			 * The hour of the day. This can be a number from 0 to 23, as times are
14991 			 * stored unambiguously in the 24-hour clock.
14992 			 * @type number
14993 			 */
14994 			this.hour = parseInt(params.hour, 10) || 0;
14995 			/**
14996 			 * The minute of the hours. Ranges from 0 to 59.
14997 			 * @type number
14998 			 */
14999 			this.minute = parseInt(params.minute, 10) || 0;
15000 			/**
15001 			 * The second of the minute. Ranges from 0 to 59.
15002 			 * @type number
15003 			 */
15004 			this.second = parseInt(params.second, 10) || 0;
15005 			/**
15006 			 * The millisecond of the second. Ranges from 0 to 999.
15007 			 * @type number
15008 			 */
15009 			this.millisecond = parseInt(params.millisecond, 10) || 0;
15010 			
15011 			/**
15012 			 * The day of the year. Ranges from 1 to 366.
15013 			 * @type number
15014 			 */
15015 			this.dayOfYear = parseInt(params.dayOfYear, 10);
15016 			
15017 			if (typeof(params.dst) === 'boolean') {
15018 				this.dst = params.dst;
15019 			}
15020 			
15021 			this.rd = this.newRd(this);
15022 			
15023 			// add the time zone offset to the rd to convert to UTC
15024 			if (!this.tz) {
15025 				this.tz = new ilib.TimeZone({id: this.timezone});
15026 			}
15027 			// getOffsetMillis requires that this.year, this.rd, and this.dst 
15028 			// are set in order to figure out which time zone rules apply and 
15029 			// what the offset is at that point in the year
15030 			this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
15031 			if (this.offset !== 0) {
15032 				this.rd = this.newRd({
15033 					rd: this.rd.getRataDie() - this.offset
15034 				});
15035 			}
15036 		}
15037 	}
15038 	
15039 	if (!this.rd) {
15040 		this.rd = this.newRd(params);
15041 		this._calcDateComponents();
15042 	}
15043 };
15044 
15045 ilib.Date.EthiopicDate.prototype = new ilib.Date({ noinstance: true });
15046 ilib.Date.EthiopicDate.prototype.parent = ilib.Date;
15047 ilib.Date.EthiopicDate.prototype.constructor = ilib.Date.EthiopicDate;
15048 
15049 /**
15050  * Return a new RD for this date type using the given params.
15051  * @protected
15052  * @param {Object=} params the parameters used to create this rata die instance
15053  * @returns {ilib.Date.RataDie} the new RD instance for the given params
15054  */
15055 ilib.Date.EthiopicDate.prototype.newRd = function (params) {
15056 	return new ilib.Date.EthiopicRataDie(params);
15057 };
15058 
15059 /**
15060  * Return the year for the given RD
15061  * @protected
15062  * @param {number} rd RD to calculate from 
15063  * @returns {number} the year for the RD
15064  */
15065 ilib.Date.EthiopicDate.prototype._calcYear = function(rd) {
15066 	var year = Math.floor((4*(Math.floor(rd)-1) + 1463)/1461);
15067 	
15068 	return year;
15069 };
15070 
15071 /**
15072  * Calculate date components for the given RD date.
15073  * @protected
15074  */
15075 ilib.Date.EthiopicDate.prototype._calcDateComponents = function () {
15076 	var remainder,
15077 		cumulative,
15078 		rd = this.rd.getRataDie();
15079 	
15080 	this.year = this._calcYear(rd);
15081 
15082 	if (typeof(this.offset) === "undefined") {
15083 		this.year = this._calcYear(rd);
15084 		
15085 		// now offset the RD by the time zone, then recalculate in case we were 
15086 		// near the year boundary
15087 		if (!this.tz) {
15088 			this.tz = new ilib.TimeZone({id: this.timezone});
15089 		}
15090 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
15091 	}
15092 
15093 	if (this.offset !== 0) {
15094 		rd += this.offset;
15095 		this.year = this._calcYear(rd);
15096 	}
15097 	
15098 	var jan1 = this.newRd({
15099 		year: this.year,
15100 		month: 1,
15101 		day: 1,
15102 		hour: 0,
15103 		minute: 0,
15104 		second: 0,
15105 		millisecond: 0
15106 	});
15107 	remainder = rd + 1 - jan1.getRataDie();
15108 	
15109 	this.month = Math.floor((remainder-1)/30) + 1;
15110 	remainder = remainder - (this.month-1) * 30;
15111 	
15112 	this.day = Math.floor(remainder);
15113 	remainder -= this.day;
15114 	// now convert to milliseconds for the rest of the calculation
15115 	remainder = Math.round(remainder * 86400000);
15116 	
15117 	this.hour = Math.floor(remainder/3600000);
15118 	remainder -= this.hour * 3600000;
15119 	
15120 	this.minute = Math.floor(remainder/60000);
15121 	remainder -= this.minute * 60000;
15122 	
15123 	this.second = Math.floor(remainder/1000);
15124 	remainder -= this.second * 1000;
15125 	
15126 	this.millisecond = remainder;
15127 };
15128 
15129 /**
15130  * Return the day of the week of this date. The day of the week is encoded
15131  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
15132  * 
15133  * @return {number} the day of the week
15134  */
15135 ilib.Date.EthiopicDate.prototype.getDayOfWeek = function() {
15136 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
15137 	return ilib.mod(rd-4, 7);
15138 };
15139 
15140 /**
15141  * Return the name of the calendar that governs this date.
15142  * 
15143  * @return {string} a string giving the name of the calendar
15144  */
15145 ilib.Date.EthiopicDate.prototype.getCalendar = function() {
15146 	return "ethiopic";
15147 };
15148 
15149 //register with the factory method
15150 ilib.Date._constructors["ethiopic"] = ilib.Date.EthiopicDate;
15151 /*
15152  * coptic.js - Represent a Coptic calendar object.
15153  * 
15154  * Copyright © 2015, JEDLSoft
15155  *
15156  * Licensed under the Apache License, Version 2.0 (the "License");
15157  * you may not use this file except in compliance with the License.
15158  * You may obtain a copy of the License at
15159  *
15160  *     http://www.apache.org/licenses/LICENSE-2.0
15161  *
15162  * Unless required by applicable law or agreed to in writing, software
15163  * distributed under the License is distributed on an "AS IS" BASIS,
15164  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15165  *
15166  * See the License for the specific language governing permissions and
15167  * limitations under the License.
15168  */
15169 
15170 
15171 /* !depends calendar.js locale.js date.js julianday.js util/utils.js util/math.js calendar/ethiopic.js */
15172 
15173 /**
15174  * @class
15175  * Construct a new Coptic calendar object. This class encodes information about
15176  * a Coptic calendar.<p>
15177  * 
15178  * Depends directive: !depends coptic.js
15179  * 
15180  * @constructor
15181  * @implements ilib.Cal
15182  */
15183 ilib.Cal.Coptic = function() {
15184 	this.type = "coptic";
15185 };
15186 
15187 ilib.Cal.Coptic.prototype = new ilib.Cal.Ethiopic();
15188 ilib.Cal.Coptic.prototype.parent = ilib.Cal.Coptic.prototype;
15189 ilib.Cal.Coptic.prototype.constructor = ilib.Cal.Coptic;
15190 
15191 /**
15192  * Return a date instance for this calendar type using the given
15193  * options.
15194  * @param {Object} options options controlling the construction of 
15195  * the date instance
15196  * @return {ilib.Date} a date appropriate for this calendar type
15197  */
15198 ilib.Cal.Coptic.prototype.newDateInstance = function (options) {
15199 	return new ilib.Date.CopticDate(options);
15200 };
15201 
15202 /* register this calendar for the factory method */
15203 ilib.Cal._constructors["coptic"] = ilib.Cal.Coptic;
15204 /*
15205  * copticdate.js - Represent a date in the Coptic calendar
15206  * 
15207  * Copyright © 2015, JEDLSoft
15208  *
15209  * Licensed under the Apache License, Version 2.0 (the "License");
15210  * you may not use this file except in compliance with the License.
15211  * You may obtain a copy of the License at
15212  *
15213  *     http://www.apache.org/licenses/LICENSE-2.0
15214  *
15215  * Unless required by applicable law or agreed to in writing, software
15216  * distributed under the License is distributed on an "AS IS" BASIS,
15217  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15218  *
15219  * See the License for the specific language governing permissions and
15220  * limitations under the License.
15221  */
15222 
15223 /* !depends 
15224 date.js 
15225 calendar/coptic.js 
15226 util/utils.js
15227 util/search.js 
15228 util/math.js
15229 localeinfo.js 
15230 julianday.js 
15231 calendar/ethiopicdate.js
15232 */
15233 
15234 /**
15235  * @class
15236  * Construct a new Coptic RD date number object. The constructor parameters can 
15237  * contain any of the following properties:
15238  * 
15239  * <ul>
15240  * <li><i>unixtime<i> - sets the time of this instance according to the given 
15241  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
15242  * 
15243  * <li><i>julianday</i> - sets the time of this instance according to the given
15244  * Julian Day instance or the Julian Day given as a float
15245  * 
15246  * <li><i>year</i> - any integer, including 0
15247  * 
15248  * <li><i>month</i> - 1 to 13, where 1 means Thoout, 2 means Paope, etc., and 13 means Epagomene
15249  * 
15250  * <li><i>day</i> - 1 to 30
15251  * 
15252  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
15253  * is always done with an unambiguous 24 hour representation
15254  * 
15255  * <li><i>minute</i> - 0 to 59
15256  * 
15257  * <li><i>second</i> - 0 to 59
15258  * 
15259  * <li><i>millisecond</i> - 0 to 999
15260  * 
15261  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
15262  * </ul>
15263  *
15264  * If the constructor is called with another Coptic date instance instead of
15265  * a parameter block, the other instance acts as a parameter block and its
15266  * settings are copied into the current instance.<p>
15267  * 
15268  * If the constructor is called with no arguments at all or if none of the 
15269  * properties listed above are present, then the RD is calculate based on 
15270  * the current date at the time of instantiation. <p>
15271  * 
15272  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
15273  * specified in the params, it is assumed that they have the smallest possible
15274  * value in the range for the property (zero or one).<p>
15275  * 
15276  * Depends directive: !depends copticdate.js
15277  * 
15278  * @private
15279  * @constructor
15280  * @extends ilib.Date.EthiopicRataDie
15281  * @param {Object=} params parameters that govern the settings and behaviour of this Coptic RD date
15282  */
15283 ilib.Date.CopticRataDie = function(params) {
15284 	this.cal = params && params.cal || new ilib.Cal.Coptic();
15285 	this.rd = undefined;
15286 	/**
15287 	 * The difference between the zero Julian day and the first Coptic date
15288 	 * of Friday, August 29, 284 CE Julian at 7:00am UTC. 
15289 	 * @private
15290 	 * @const
15291 	 * @type number
15292 	 */
15293 	this.epoch = 1825028.5;
15294 
15295 	var tmp = {};
15296 	if (params) {
15297 		ilib.shallowCopy(params, tmp);
15298 	}
15299 	tmp.cal = this.cal; // override the cal parameter that may be passed in
15300 	ilib.Date.EthiopicRataDie.call(this, tmp);
15301 };
15302 
15303 ilib.Date.CopticRataDie.prototype = new ilib.Date.EthiopicRataDie();
15304 ilib.Date.CopticRataDie.prototype.parent = ilib.Date.EthiopicRataDie;
15305 ilib.Date.CopticRataDie.prototype.constructor = ilib.Date.CopticRataDie;
15306 
15307 /**
15308  * @class
15309  * Construct a new date object for the Coptic Calendar. The constructor can be called
15310  * with a parameter object that contains any of the following properties:
15311  * 
15312  * <ul>
15313  * <li><i>unixtime<i> - sets the time of this instance according to the given 
15314  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970 (Gregorian).
15315  * <li><i>julianday</i> - the Julian Day to set into this date
15316  * <li><i>year</i> - any integer
15317  * <li><i>month</i> - 1 to 13, where 1 means Thoout, 2 means Paope, etc., and 13 means Epagomene
15318  * <li><i>day</i> - 1 to 30
15319  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
15320  * is always done with an unambiguous 24 hour representation
15321  * <li><i>minute</i> - 0 to 59
15322  * <li><i>second</i> - 0 to 59
15323  * <li><i>millisecond<i> - 0 to 999
15324  * <li><i>locale</i> - the ilib.TimeZone instance or time zone name as a string 
15325  * of this coptic date. The date/time is kept in the local time. The time zone
15326  * is used later if this date is formatted according to a different time zone and
15327  * the difference has to be calculated, or when the date format has a time zone
15328  * component in it.
15329  * <li><i>timezone</i> - the time zone of this instance. If the time zone is not 
15330  * given, it can be inferred from this locale. For locales that span multiple
15331  * time zones, the one with the largest population is chosen as the one that 
15332  * represents the locale. 
15333  * 
15334  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
15335  * </ul>
15336  *  
15337  * If called with another Coptic date argument, the date components of the given
15338  * date are copied into the current one.<p>
15339  * 
15340  * If the constructor is called with no arguments at all or if none of the 
15341  * properties listed above 
15342  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
15343  * components are 
15344  * filled in with the current date at the time of instantiation. Note that if
15345  * you do not give the time zone when defaulting to the current time and the 
15346  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
15347  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
15348  * Mean Time").<p>
15349  * 
15350  * Depends directive: !depends copticdate.js
15351  * 
15352  * @constructor
15353  * @extends ilib.Date.EthiopicDate
15354  * @param {Object=} params parameters that govern the settings and behaviour of this Coptic date
15355  */
15356 ilib.Date.CopticDate = function(params) {
15357 	this.rd = undefined; // clear these out so that the EthiopicDate constructor can set it
15358 	ilib.Date.EthiopicDate.call(this, params);
15359 	this.cal = new ilib.Cal.Coptic();
15360 };
15361 
15362 ilib.Date.CopticDate.prototype = new ilib.Date.EthiopicDate({noinstance: true});
15363 ilib.Date.CopticDate.prototype.parent = ilib.Date.EthiopicDate.prototype;
15364 ilib.Date.CopticDate.prototype.constructor = ilib.Date.CopticDate;
15365 
15366 /**
15367  * Return a new RD for this date type using the given params.
15368  * @protected
15369  * @param {Object=} params the parameters used to create this rata die instance
15370  * @returns {ilib.Date.RataDie} the new RD instance for the given params
15371  */
15372 ilib.Date.CopticDate.prototype.newRd = function (params) {
15373 	return new ilib.Date.CopticRataDie(params);
15374 };
15375 
15376 /**
15377  * Return the day of the week of this date. The day of the week is encoded
15378  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
15379  * 
15380  * @return {number} the day of the week
15381  */
15382 ilib.Date.CopticDate.prototype.getDayOfWeek = function() {
15383 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
15384 	return ilib.mod(rd-3, 7);
15385 };
15386 
15387 /**
15388  * Return the name of the calendar that governs this date.
15389  * 
15390  * @return {string} a string giving the name of the calendar
15391  */
15392 ilib.Date.CopticDate.prototype.getCalendar = function() {
15393 	return "coptic";
15394 };
15395 
15396 //register with the factory method
15397 ilib.Date._constructors["coptic"] = ilib.Date.CopticDate;
15398 /*
15399  * ctype.js - Character type definitions
15400  * 
15401  * Copyright © 2012-2014, JEDLSoft
15402  *
15403  * Licensed under the Apache License, Version 2.0 (the "License");
15404  * you may not use this file except in compliance with the License.
15405  * You may obtain a copy of the License at
15406  *
15407  *     http://www.apache.org/licenses/LICENSE-2.0
15408  *
15409  * Unless required by applicable law or agreed to in writing, software
15410  * distributed under the License is distributed on an "AS IS" BASIS,
15411  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15412  *
15413  * See the License for the specific language governing permissions and
15414  * limitations under the License.
15415  */
15416 
15417 // !depends ilibglobal.js locale.js util/search.js
15418 
15419 // !data ctype
15420 
15421 /**
15422  * Provides a set of static routines that return information about characters.
15423  * These routines emulate the C-library ctype functions. The characters must be 
15424  * encoded in utf-16, as no other charsets are currently supported. Only the first
15425  * character of the given string is tested.
15426  * @namespace
15427  */
15428 ilib.CType = {
15429 	/**
15430 	 * Actual implementation for withinRange. Searches the given object for ranges.
15431 	 * The range names are taken from the Unicode range names in 
15432 	 * http://www.unicode.org/Public/UNIDATA/extracted/DerivedGeneralCategory.txt
15433 	 * 
15434 	 * <ul>
15435 	 * <li>Cn - Unassigned
15436 	 * <li>Lu - Uppercase_Letter
15437 	 * <li>Ll - Lowercase_Letter
15438 	 * <li>Lt - Titlecase_Letter
15439 	 * <li>Lm - Modifier_Letter
15440 	 * <li>Lo - Other_Letter
15441 	 * <li>Mn - Nonspacing_Mark
15442 	 * <li>Me - Enclosing_Mark
15443 	 * <li>Mc - Spacing_Mark
15444 	 * <li>Nd - Decimal_Number
15445 	 * <li>Nl - Letter_Number
15446 	 * <li>No - Other_Number
15447 	 * <li>Zs - Space_Separator
15448 	 * <li>Zl - Line_Separator
15449 	 * <li>Zp - Paragraph_Separator
15450 	 * <li>Cc - Control
15451 	 * <li>Cf - Format
15452 	 * <li>Co - Private_Use
15453 	 * <li>Cs - Surrogate
15454 	 * <li>Pd - Dash_Punctuation
15455 	 * <li>Ps - Open_Punctuation
15456 	 * <li>Pe - Close_Punctuation
15457 	 * <li>Pc - Connector_Punctuation
15458 	 * <li>Po - Other_Punctuation
15459 	 * <li>Sm - Math_Symbol
15460 	 * <li>Sc - Currency_Symbol
15461 	 * <li>Sk - Modifier_Symbol
15462 	 * <li>So - Other_Symbol
15463 	 * <li>Pi - Initial_Punctuation
15464 	 * <li>Pf - Final_Punctuation
15465 	 * </ul>
15466 	 * 
15467 	 * @protected
15468 	 * @param {number} num code point of the character to examine
15469 	 * @param {string} rangeName the name of the range to check
15470 	 * @param {Object} obj object containing the character range data
15471 	 * @return {boolean} true if the first character is within the named
15472 	 * range
15473 	 */
15474 	_inRange: function(num, rangeName, obj) {
15475 		var range, i;
15476 		if (num < 0 || !rangeName || !obj) {
15477 			return false;
15478 		}
15479 		
15480 		range = obj[rangeName];
15481 		if (!range) {
15482 			return false;
15483 		}
15484 		
15485 		var compare = function(singlerange, target) {
15486 			if (singlerange.length === 1) {
15487 				return singlerange[0] - target;
15488 			} else {
15489 				return target < singlerange[0] ? singlerange[0] - target :
15490 					(target > singlerange[1] ? singlerange[1] - target : 0);
15491 			}
15492 		};
15493 		var result = ilib.bsearch(num, range, compare);
15494 		return result < range.length && compare(range[result], num) === 0;
15495 	},
15496 	
15497 	/**
15498 	 * Return whether or not the first character is within the named range
15499 	 * of Unicode characters. The valid list of range names are taken from 
15500 	 * the Unicode 6.0 spec. Characters in all ranges of Unicode are supported,
15501 	 * including those supported in Javascript via UTF-16. Currently, this method 
15502 	 * supports the following range names:
15503 	 * 
15504 	 * <ul>
15505 	 * <li><i>ascii</i> - basic ASCII
15506 	 * <li><i>latin</i> - Latin, Latin Extended Additional, Latin Extended-C, Latin Extended-D
15507 	 * <li><i>armenian</i>
15508 	 * <li><i>greek</i> - Greek, Greek Extended
15509 	 * <li><i>cyrillic</i> - Cyrillic, Cyrillic Extended-A, Cyrillic Extended-B
15510 	 * <li><i>georgian</i> - Georgian, Georgian Supplement
15511 	 * <li><i>glagolitic</i>
15512 	 * <li><i>gothic</i>
15513 	 * <li><i>ogham</i>
15514 	 * <li><i>oldpersian</i>
15515 	 * <li><i>runic</i>
15516 	 * <li><i>ipa</i> - IPA, Phonetic Extensions, Phonetic Extensions Supplement
15517 	 * <li><i>phonetic</i>
15518 	 * <li><i>modifiertone</i> - Modifier Tone Letters
15519 	 * <li><i>spacing</i>
15520 	 * <li><i>diacritics</i>
15521 	 * <li><i>halfmarks</i> - Combining Half Marks
15522 	 * <li><i>small</i> - Small Form Variants
15523 	 * <li><i>bamum</i> - Bamum, Bamum Supplement
15524 	 * <li><i>ethiopic</i> - Ethiopic, Ethiopic Extended, Ethiopic Extended-A
15525 	 * <li><i>nko</i>
15526 	 * <li><i>osmanya</i>
15527 	 * <li><i>tifinagh</i>
15528 	 * <li><i>val</i>
15529 	 * <li><i>arabic</i> - Arabic, Arabic Supplement, Arabic Presentation Forms-A, 
15530 	 * Arabic Presentation Forms-B
15531 	 * <li><i>carlan</i>
15532 	 * <li><i>hebrew</i>
15533 	 * <li><i>mandaic</i>
15534 	 * <li><i>samaritan</i>
15535 	 * <li><i>syriac</i>
15536 	 * <li><i>mongolian</i>
15537 	 * <li><i>phagspa</i>
15538 	 * <li><i>tibetan</i>
15539 	 * <li><i>bengali</i>
15540 	 * <li><i>devanagari</i> - Devanagari, Devanagari Extended
15541 	 * <li><i>gujarati</i>
15542 	 * <li><i>gurmukhi</i>
15543 	 * <li><i>kannada</i>
15544 	 * <li><i>lepcha</i>
15545 	 * <li><i>limbu</i>
15546 	 * <li><i>malayalam</i>
15547 	 * <li><i>meetaimayek</i>
15548 	 * <li><i>olchiki</i>
15549 	 * <li><i>oriya</i>
15550 	 * <li><i>saurashtra</i>
15551 	 * <li><i>sinhala</i>
15552 	 * <li><i>sylotinagri</i> - Syloti Nagri
15553 	 * <li><i>tamil</i>
15554 	 * <li><i>telugu</i>
15555 	 * <li><i>thaana</i>
15556 	 * <li><i>vedic</i>
15557 	 * <li><i>batak</i>
15558 	 * <li><i>balinese</i>
15559 	 * <li><i>buginese</i>
15560 	 * <li><i>cham</i>
15561 	 * <li><i>javanese</i>
15562 	 * <li><i>kayahli</i>
15563 	 * <li><i>khmer</i>
15564 	 * <li><i>lao</i>
15565 	 * <li><i>myanmar</i> - Myanmar, Myanmar Extended-A
15566 	 * <li><i>newtailue</i>
15567 	 * <li><i>rejang</i>
15568 	 * <li><i>sundanese</i>
15569 	 * <li><i>taile</i>
15570 	 * <li><i>taitham</i>
15571 	 * <li><i>taiviet</i>
15572 	 * <li><i>thai</i>
15573 	 * <li><i>buhld</i>
15574 	 * <li><i>hanunoo</i>
15575 	 * <li><i>tagalog</i>
15576 	 * <li><i>tagbanwa</i>
15577 	 * <li><i>bopomofo</i> - Bopomofo, Bopomofo Extended
15578 	 * <li><i>cjk</i> - the CJK unified ideographs (Han), CJK Unified Ideographs
15579 	 *  Extension A, CJK Unified Ideographs Extension B, CJK Unified Ideographs 
15580 	 *  Extension C, CJK Unified Ideographs Extension D, Ideographic Description 
15581 	 *  Characters (=isIdeo())
15582 	 * <li><i>cjkcompatibility</i> - CJK Compatibility, CJK Compatibility 
15583 	 * Ideographs, CJK Compatibility Forms, CJK Compatibility Ideographs Supplement
15584 	 * <li><i>cjkradicals</i> - the CJK radicals, KangXi radicals
15585 	 * <li><i>hangul</i> - Hangul Jamo, Hangul Syllables, Hangul Jamo Extended-A, 
15586 	 * Hangul Jamo Extended-B, Hangul Compatibility Jamo
15587 	 * <li><i>cjkpunct</i> - CJK symbols and punctuation
15588 	 * <li><i>cjkstrokes</i> - CJK strokes
15589 	 * <li><i>hiragana</i>
15590 	 * <li><i>katakana</i> - Katakana, Katakana Phonetic Extensions, Kana Supplement
15591 	 * <li><i>kanbun</i>
15592 	 * <li><i>lisu</i>
15593 	 * <li><i>yi</i> - Yi Syllables, Yi Radicals
15594 	 * <li><i>cherokee</i>
15595 	 * <li><i>canadian</i> - Unified Canadian Aboriginal Syllabics, Unified Canadian 
15596 	 * Aboriginal Syllabics Extended
15597 	 * <li><i>presentation</i> - Alphabetic presentation forms
15598 	 * <li><i>vertical</i> - Vertical Forms
15599 	 * <li><i>width</i> - Halfwidth and Fullwidth Forms
15600 	 * <li><i>punctuation</i> - General punctuation, Supplemental Punctuation
15601 	 * <li><i>box</i> - Box Drawing
15602 	 * <li><i>block</i> - Block Elements
15603 	 * <li><i>letterlike</i> - Letterlike symbols
15604 	 * <li><i>mathematical</i> - Mathematical alphanumeric symbols, Miscellaneous 
15605 	 * Mathematical Symbols-A, Miscellaneous Mathematical Symbols-B
15606 	 * <li><i>enclosedalpha</i> - Enclosed alphanumerics, Enclosed Alphanumeric Supplement
15607 	 * <li><i>enclosedcjk</i> - Enclosed CJK letters and months, Enclosed Ideographic Supplement
15608 	 * <li><i>cjkcompatibility</i> - CJK compatibility
15609 	 * <li><i>apl</i> - APL symbols
15610 	 * <li><i>controlpictures</i> - Control pictures
15611 	 * <li><i>misc</i> - Miscellaneous technical
15612 	 * <li><i>ocr</i> - Optical character recognition (OCR)
15613 	 * <li><i>combining</i> - Combining Diacritical Marks, Combining Diacritical Marks 
15614 	 * for Symbols, Combining Diacritical Marks Supplement
15615 	 * <li><i>digits</i> - ASCII digits (=isDigit())
15616 	 * <li><i>indicnumber</i> - Common Indic Number Forms
15617 	 * <li><i>numbers</i> - Number dorms
15618 	 * <li><i>supersub</i> - Super- and subscripts
15619 	 * <li><i>arrows</i> - Arrows, Miscellaneous Symbols and Arrows, Supplemental Arrows-A,
15620 	 * Supplemental Arrows-B
15621 	 * <li><i>operators</i> - Mathematical operators, supplemental 
15622 	 * mathematical operators 
15623 	 * <li><i>geometric</i> - Geometric shapes
15624 	 * <li><i>ancient</i> - Ancient symbols
15625 	 * <li><i>braille</i> - Braille patterns
15626 	 * <li><i>currency</i> - Currency symbols
15627 	 * <li><i>dingbats</i>
15628 	 * <li><i>gamesymbols</i>
15629 	 * <li><i>yijing</i> - Yijing Hexagram Symbols
15630 	 * <li><i>specials</i>
15631 	 * <li><i>variations</i> - Variation Selectors, Variation Selectors Supplement
15632 	 * <li><i>privateuse</i> - Private Use Area, Supplementary Private Use Area-A, 
15633 	 * Supplementary Private Use Area-B
15634 	 * <li><i>supplementarya</i> - Supplementary private use area-A
15635 	 * <li><i>supplementaryb</i> - Supplementary private use area-B
15636 	 * <li><i>highsurrogates</i> - High Surrogates, High Private Use Surrogates
15637 	 * <li><i>lowsurrogates</i>
15638 	 * <li><i>reserved</i>
15639 	 * <li><i>noncharacters</i>
15640 	 * </ul><p>
15641 	 * 
15642 	 * Depends directive: !depends ctype.js
15643 	 * 
15644 	 * @param {string|ilib.String|number} ch character or code point to examine
15645 	 * @param {string} rangeName the name of the range to check
15646 	 * @return {boolean} true if the first character is within the named
15647 	 * range
15648 	 */
15649 	withinRange: function(ch, rangeName) {
15650 		if (!rangeName) {
15651 			return false;
15652 		}
15653 		var num;
15654 		switch (typeof(ch)) {
15655 			case 'number':
15656 				num = ch;
15657 				break;
15658 			case 'string':
15659 				num = ilib.String.toCodePoint(ch, 0);
15660 				break;
15661 			case 'undefined':
15662 				return false;
15663 			default:
15664 				num = ch._toCodePoint(0);
15665 				break;
15666 		}
15667 
15668 		return ilib.CType._inRange(num, rangeName.toLowerCase(), ilib.data.ctype);
15669 	},
15670 	
15671 	/**
15672 	 * @protected
15673 	 * @param {boolean} sync
15674 	 * @param {Object} loadParams
15675 	 * @param {function(*)|undefined} onLoad
15676 	 */
15677 	_init: function(sync, loadParams, onLoad) {
15678 		ilib.CType._load("ctype", sync, loadParams, onLoad);
15679 	},
15680 	
15681 	/**
15682 	 * @protected
15683 	 * @param {string} name
15684 	 * @param {boolean} sync
15685 	 * @param {Object} loadParams
15686 	 * @param {function(*)|undefined} onLoad
15687 	 */
15688 	_load: function (name, sync, loadParams, onLoad) {
15689 		if (!ilib.data[name]) {
15690 			var loadName = name ? name + ".json" : "ctype.json";
15691 			ilib.loadData({
15692 				name: loadName,
15693 				locale: "-",
15694 				nonlocale: true,
15695 				sync: sync,
15696 				loadParams: loadParams, 
15697 				callback: /** @type function(Object=):undefined */ ilib.bind(this, /** @type function() */ function(ct) {
15698 					ilib.data[name] = ct;
15699 					if (onLoad && typeof(onLoad) === 'function') {
15700 						onLoad(ilib.data[name]);
15701 					}
15702 				})
15703 			});
15704 		} else {
15705 			if (onLoad && typeof(onLoad) === 'function') {
15706 				onLoad(ilib.data[name]);
15707 			}
15708 		}
15709 	}
15710 };
15711 
15712 /*
15713  * ctype.isdigit.js - Character type is digit
15714  * 
15715  * Copyright © 2012-2013, JEDLSoft
15716  *
15717  * Licensed under the Apache License, Version 2.0 (the "License");
15718  * you may not use this file except in compliance with the License.
15719  * You may obtain a copy of the License at
15720  *
15721  *     http://www.apache.org/licenses/LICENSE-2.0
15722  *
15723  * Unless required by applicable law or agreed to in writing, software
15724  * distributed under the License is distributed on an "AS IS" BASIS,
15725  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15726  *
15727  * See the License for the specific language governing permissions and
15728  * limitations under the License.
15729  */
15730 
15731 // !depends ctype.js
15732 
15733 // !data ctype
15734 
15735 /**
15736  * Return whether or not the first character is a digit character in the
15737  * Latin script.<p>
15738  * 
15739  * Depends directive: !depends ctype.isdigit.js
15740  * 
15741  * @param {string|ilib.String|number} ch character or code point to examine
15742  * @return {boolean} true if the first character is a digit character in the
15743  * Latin script. 
15744  */
15745 ilib.CType.isDigit = function (ch) {
15746 	var num;
15747 	switch (typeof(ch)) {
15748 		case 'number':
15749 			num = ch;
15750 			break;
15751 		case 'string':
15752 			num = ilib.String.toCodePoint(ch, 0);
15753 			break;
15754 		case 'undefined':
15755 			return false;
15756 		default:
15757 			num = ch._toCodePoint(0);
15758 			break;
15759 	}
15760 	return ilib.CType._inRange(num, 'digit', ilib.data.ctype);
15761 };
15762 
15763 /**
15764  * @protected
15765  * @param {boolean} sync
15766  * @param {Object} loadParams
15767  * @param {function(*)|undefined} onLoad
15768  */
15769 ilib.CType.isDigit._init = function (sync, loadParams, onLoad) {
15770 	ilib.CType._init(sync, loadParams, onLoad);
15771 };
15772 
15773 /*
15774  * ctype.isspace.js - Character type is space char
15775  * 
15776  * Copyright © 2012-2013, JEDLSoft
15777  *
15778  * Licensed under the Apache License, Version 2.0 (the "License");
15779  * you may not use this file except in compliance with the License.
15780  * You may obtain a copy of the License at
15781  *
15782  *     http://www.apache.org/licenses/LICENSE-2.0
15783  *
15784  * Unless required by applicable law or agreed to in writing, software
15785  * distributed under the License is distributed on an "AS IS" BASIS,
15786  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15787  *
15788  * See the License for the specific language governing permissions and
15789  * limitations under the License.
15790  */
15791 
15792 // !depends ctype.js
15793 
15794 // !data ctype ctype_z
15795 
15796 /**
15797  * Return whether or not the first character is a whitespace character.<p>
15798  * 
15799  * Depends directive: !depends ctype.isspace.js
15800  * 
15801  * @param {string|ilib.String|number} ch character or code point to examine
15802  * @return {boolean} true if the first character is a whitespace character.
15803  */
15804 ilib.CType.isSpace = function (ch) {
15805 	var num;
15806 	switch (typeof(ch)) {
15807 		case 'number':
15808 			num = ch;
15809 			break;
15810 		case 'string':
15811 			num = ilib.String.toCodePoint(ch, 0);
15812 			break;
15813 		case 'undefined':
15814 			return false;
15815 		default:
15816 			num = ch._toCodePoint(0);
15817 			break;
15818 	}
15819 
15820 	return ilib.CType._inRange(num, 'space', ilib.data.ctype) ||
15821 		ilib.CType._inRange(num, 'Zs', ilib.data.ctype_z) ||
15822 		ilib.CType._inRange(num, 'Zl', ilib.data.ctype_z) ||
15823 		ilib.CType._inRange(num, 'Zp', ilib.data.ctype_z);
15824 };
15825 
15826 /**
15827  * @protected
15828  * @param {boolean} sync
15829  * @param {Object} loadParams
15830  * @param {function(*)|undefined} onLoad
15831  */
15832 ilib.CType.isSpace._init = function (sync, loadParams, onLoad) {
15833 	ilib.CType._load("ctype_z", sync, loadParams, function () {
15834 		ilib.CType._init(sync, loadParams, onLoad);
15835 	});
15836 };
15837 
15838 /*
15839  * numprs.js - Parse a number in any locale
15840  * 
15841  * Copyright © 2012-2014, JEDLSoft
15842  *
15843  * Licensed under the Apache License, Version 2.0 (the "License");
15844  * you may not use this file except in compliance with the License.
15845  * You may obtain a copy of the License at
15846  *
15847  *     http://www.apache.org/licenses/LICENSE-2.0
15848  *
15849  * Unless required by applicable law or agreed to in writing, software
15850  * distributed under the License is distributed on an "AS IS" BASIS,
15851  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15852  *
15853  * See the License for the specific language governing permissions and
15854  * limitations under the License.
15855  */
15856 
15857 /*
15858 !depends 
15859 ilibglobal.js 
15860 locale.js 
15861 strings.js 
15862 ctype.isdigit.js 
15863 ctype.isspace.js
15864 */
15865 
15866 /**
15867  * @class
15868  * Parse a string as a number, ignoring all locale-specific formatting.<p>
15869  * 
15870  * This class is different from the standard Javascript parseInt() and parseFloat() 
15871  * functions in that the number to be parsed can have formatting characters in it 
15872  * that are not supported by those two
15873  * functions, and it handles numbers written in other locales properly. For example, 
15874  * if you pass the string "203,231.23" to the parseFloat() function in Javascript, it 
15875  * will return you the number 203. The ilib.Number class will parse it correctly and 
15876  * the value() function will return the number 203231.23. If you pass parseFloat() the 
15877  * string "203.231,23" with the locale set to de-DE, it will return you 203 again. This
15878  * class will return the correct number 203231.23 again.<p>
15879  * 
15880  * The options object may contain any of the following properties:
15881  * 
15882  * <ul>
15883  * <li><i>locale</i> - specify the locale of the string to parse. This is used to
15884  * figure out what the decimal point character is. If not specified, the default locale
15885  * for the app or browser is used.
15886  * <li><i>type</i> - specify whether this string should be interpretted as a number,
15887  * currency, or percentage amount. When the number is interpretted as a currency
15888  * amount, the getCurrency() method will return something useful, otherwise it will
15889  * return undefined. If
15890  * the number is to be interpretted as percentage amount and there is a percentage sign
15891  * in the string, then the number will be returned
15892  * as a fraction from the valueOf() method. If there is no percentage sign, then the 
15893  * number will be returned as a regular number. That is "58.3%" will be returned as the 
15894  * number 0.583 but "58.3" will be returned as 58.3. Valid values for this property 
15895  * are "number", "currency", and "percentage". Default if this is not specified is
15896  * "number".
15897  * <li><i>onLoad</i> - a callback function to call when the locale data is fully 
15898  * loaded. When the onLoad option is given, this class will attempt to
15899  * load any missing locale data using the ilib loader callback.
15900  * When the constructor is done (even if the data is already preassembled), the 
15901  * onLoad function is called with the current instance as a parameter, so this
15902  * callback can be used with preassembled or dynamic loading or a mix of the two. 
15903  * 
15904  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
15905  * asynchronously. If this option is given as "false", then the "onLoad"
15906  * callback must be given, as the instance returned from this constructor will
15907  * not be usable for a while.
15908  *  
15909  * <li><i>loadParams</i> - an object containing parameters to pass to the 
15910  * loader callback function when locale data is missing. The parameters are not
15911  * interpretted or modified in any way. They are simply passed along. The object 
15912  * may contain any property/value pairs as long as the calling code is in
15913  * agreement with the loader callback function as to what those parameters mean.
15914  * </ul>
15915  * <p>
15916  * 
15917  * Depends directive: !depends numprs.js
15918  * 
15919  * @constructor
15920  * @param {string|number|Number|ilib.Number|undefined} str a string to parse as a number, or a number value
15921  * @param {Object=} options Options controlling how the instance should be created 
15922  */
15923 ilib.Number = function (str, options) {
15924 	var i, stripped = "", 
15925 		sync = true,
15926 		loadParams,
15927 		onLoad;
15928 	
15929 	this.locale = new ilib.Locale();
15930 	this.type = "number";
15931 	
15932 	if (options) {
15933 		if (options.locale) {
15934 			this.locale = (typeof(options.locale) === 'string') ? new ilib.Locale(options.locale) : options.locale;
15935 		}
15936 		if (options.type) {
15937 			switch (options.type) {
15938 				case "number":
15939 				case "currency":
15940 				case "percentage":
15941 					this.type = options.type;
15942 					break;
15943 				default:
15944 					break;
15945 			}
15946 		}
15947 		if (typeof(options.sync) !== 'undefined') {
15948 			sync = (options.sync == true);
15949 		}
15950 		loadParams = options.loadParams;
15951 		onLoad = options.onLoad;
15952 	}
15953 	
15954 	ilib.CType.isDigit._init(sync, loadParams, /** @type {function()|undefined} */ ilib.bind(this, function() {
15955 		ilib.CType.isSpace._init(sync, loadParams, /** @type {function()|undefined} */ ilib.bind(this, function() {
15956 			new ilib.LocaleInfo(this.locale, {
15957 				sync: sync,
15958 				onLoad: ilib.bind(this, function (li) {
15959 					this.decimal = li.getDecimalSeparator();
15960 					
15961 					switch (typeof(str)) {
15962 					case 'string':
15963 						// stripping should work for all locales, because you just ignore all the
15964 						// formatting except the decimal char
15965 						var unary = true; // looking for the unary minus still?
15966 						this.str = str || "0";
15967 						i = 0;
15968 						for (i = 0; i < this.str.length; i++) {
15969 							if (unary && this.str.charAt(i) === '-') {
15970 								unary = false;
15971 								stripped += this.str.charAt(i);
15972 							} else if (ilib.CType.isDigit(this.str.charAt(i))) {
15973 								stripped += this.str.charAt(i);
15974 								unary = false;
15975 							} else if (this.str.charAt(i) === this.decimal) {
15976 								stripped += "."; // always convert to period
15977 								unary = false;
15978 							} // else ignore
15979 						}
15980 						this.value = parseFloat(stripped);
15981 						break;
15982 					case 'number':
15983 						this.str = "" + str;
15984 						this.value = str;
15985 						break;
15986 						
15987 					case 'object':
15988 						this.value = /** @type {number} */ str.valueOf();
15989 						this.str = "" + this.value;
15990 						break;
15991 						
15992 					case 'undefined':
15993 						this.value = 0;
15994 						this.str = "0";
15995 						break;
15996 					}
15997 					
15998 					switch (this.type) {
15999 						default:
16000 							// don't need to do anything special for other types
16001 							break;
16002 						case "percentage":
16003 							if (this.str.indexOf(li.getPercentageSymbol()) !== -1) {
16004 								this.value /= 100;
16005 							}
16006 							break;
16007 						case "currency":
16008 							stripped = "";
16009 							i = 0;
16010 							while (i < this.str.length &&
16011 								   !ilib.CType.isDigit(this.str.charAt(i)) &&
16012 								   !ilib.CType.isSpace(this.str.charAt(i))) {
16013 								stripped += this.str.charAt(i++);
16014 							}
16015 							if (stripped.length === 0) {
16016 								while (i < this.str.length && 
16017 									   ilib.CType.isDigit(this.str.charAt(i)) ||
16018 									   ilib.CType.isSpace(this.str.charAt(i)) ||
16019 									   this.str.charAt(i) === '.' ||
16020 									   this.str.charAt(i) === ',' ) {
16021 									i++;
16022 								}
16023 								while (i < this.str.length && 
16024 									   !ilib.CType.isDigit(this.str.charAt(i)) &&
16025 									   !ilib.CType.isSpace(this.str.charAt(i))) {
16026 									stripped += this.str.charAt(i++);
16027 								}
16028 							}
16029 							new ilib.Currency({
16030 								locale: this.locale, 
16031 								sign: stripped,
16032 								sync: sync,
16033 								onLoad: ilib.bind(this, function (cur) {
16034 									this.currency = cur;
16035 									if (options && typeof(options.onLoad) === 'function') {
16036 										options.onLoad(this);
16037 									}				
16038 								})
16039 							});
16040 							return;
16041 					}
16042 					
16043 					if (options && typeof(options.onLoad) === 'function') {
16044 						options.onLoad(this);
16045 					}
16046 				})
16047 			});
16048 		}));
16049 	}));
16050 };
16051 
16052 ilib.Number.prototype = {
16053 	/**
16054 	 * Return the locale for this formatter instance.
16055 	 * @return {ilib.Locale} the locale instance for this formatter
16056 	 */
16057 	getLocale: function () {
16058 		return this.locale;
16059 	},
16060 	
16061 	/**
16062 	 * Return the original string that this number instance was created with.
16063 	 * @return {string} the original string
16064 	 */
16065 	toString: function () {
16066 		return this.str;
16067 	},
16068 	
16069 	/**
16070 	 * If the type of this Number instance is "currency", then the parser will attempt
16071 	 * to figure out which currency this amount represents. The amount can be written
16072 	 * with any of the currency signs or ISO 4217 codes that are currently
16073 	 * recognized by ilib, and the currency signs may occur before or after the
16074 	 * numeric portion of the string. If no currency can be recognized, then the 
16075 	 * default currency for the locale is returned. If multiple currencies can be
16076 	 * recognized (for example if the currency sign is "$"), then this method 
16077 	 * will prefer the one for the current locale. If multiple currencies can be
16078 	 * recognized, but none are used in the current locale, then the first currency
16079 	 * encountered will be used. This may produce random results, though the larger
16080 	 * currencies occur earlier in the list. For example, if the sign found in the
16081 	 * string is "$" and that is not the sign of the currency of the current locale
16082 	 * then the US dollar will be recognized, as it is the largest currency that uses
16083 	 * the "$" as its sign.
16084 	 * 
16085 	 * @return {ilib.Currency|undefined} the currency instance for this amount, or 
16086 	 * undefined if this Number object is not of type currency
16087 	 */
16088 	getCurrency: function () {
16089 		return this.currency;
16090 	},
16091 	
16092 	/**
16093 	 * Return the value of this number object as a primitive number instance.
16094 	 * @return {number} the value of this number instance
16095 	 */
16096 	valueOf: function () {
16097 		return this.value;
16098 	}
16099 };
16100 
16101 /*
16102  * currency.js - Currency definition
16103  * 
16104  * Copyright © 2012-2014, JEDLSoft
16105  *
16106  * Licensed under the Apache License, Version 2.0 (the "License");
16107  * you may not use this file except in compliance with the License.
16108  * You may obtain a copy of the License at
16109  *
16110  *     http://www.apache.org/licenses/LICENSE-2.0
16111  *
16112  * Unless required by applicable law or agreed to in writing, software
16113  * distributed under the License is distributed on an "AS IS" BASIS,
16114  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16115  *
16116  * See the License for the specific language governing permissions and
16117  * limitations under the License.
16118  */
16119 
16120 // !depends ilibglobal.js locale.js
16121 
16122 // !data currency
16123 
16124 /**
16125  * @class
16126  * Create a new currency information instance. Instances of this class encode 
16127  * information about a particular currency.<p>
16128  * 
16129  * Note: that if you are looking to format currency for display, please see
16130  * the number formatting class {ilib.NumFmt}. This class only gives information
16131  * about currencies.<p> 
16132  * 
16133  * The options can contain any of the following properties:
16134  * 
16135  * <ul>
16136  * <li><i>locale</i> - specify the locale for this instance
16137  * <li><i>code</i> - find info on a specific currency with the given ISO 4217 code 
16138  * <li><i>sign</i> - search for a currency that uses this sign
16139  * <li><i>onLoad</i> - a callback function to call when the currency data is fully 
16140  * loaded. When the onLoad option is given, this class will attempt to
16141  * load any missing locale data using the ilib loader callback.
16142  * When the constructor is done (even if the data is already preassembled), the 
16143  * onLoad function is called with the current instance as a parameter, so this
16144  * callback can be used with preassembled or dynamic loading or a mix of the two. 
16145  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
16146  * asynchronously. If this option is given as "false", then the "onLoad"
16147  * callback must be given, as the instance returned from this constructor will
16148  * not be usable for a while.
16149  * <li><i>loadParams</i> - an object containing parameters to pass to the 
16150  * loader callback function when locale data is missing. The parameters are not
16151  * interpretted or modified in any way. They are simply passed along. The object 
16152  * may contain any property/value pairs as long as the calling code is in
16153  * agreement with the loader callback function as to what those parameters mean.
16154  * </ul>
16155  * 
16156  * When searching for a currency by its sign, this class cannot guarantee 
16157  * that it will return info about a specific currency. The reason is that currency 
16158  * signs are sometimes shared between different currencies and the sign is 
16159  * therefore ambiguous. If you need a 
16160  * guarantee, find the currency using the code instead.<p>
16161  * 
16162  * The way this class finds a currency by sign is the following. If the sign is 
16163  * unambiguous, then
16164  * the currency is returned. If there are multiple currencies that use the same
16165  * sign, and the current locale uses that sign, then the default currency for
16166  * the current locale is returned. If there are multiple, but the current locale
16167  * does not use that sign, then the currency with the largest circulation is
16168  * returned. For example, if you are in the en-GB locale, and the sign is "$",
16169  * then this class will notice that there are multiple currencies with that
16170  * sign (USD, CAD, AUD, HKD, MXP, etc.) Since "$" is not used in en-GB, it will 
16171  * pick the one with the largest circulation, which in this case is the US Dollar
16172  * (USD).<p>
16173  * 
16174  * If neither the code or sign property is set, the currency that is most common 
16175  * for the locale
16176  * will be used instead. If the locale is not set, the default locale will be used.
16177  * If the code is given, but it is not found in the list of known currencies, this
16178  * constructor will throw an exception. If the sign is given, but it is not found,
16179  * this constructor will default to the currency for the current locale. If both
16180  * the code and sign properties are given, then the sign property will be ignored
16181  * and only the code property used. If the locale is given, but it is not a known
16182  * locale, this class will default to the default locale instead.<p>
16183  * 
16184  * Depends directive: !depends currency.js
16185  * 
16186  * @constructor
16187  * @param options {Object} a set of properties to govern how this instance is constructed.
16188  * @throws "currency xxx is unknown" when the given currency code is not in the list of 
16189  * known currencies. xxx is replaced with the requested code.
16190  */
16191 ilib.Currency = function (options) {
16192 	this.sync = true;
16193 	
16194 	if (options) {
16195 		if (options.code) {
16196 			this.code = options.code;
16197 		}
16198 		if (options.locale) {
16199 			this.locale = (typeof(options.locale) === 'string') ? new ilib.Locale(options.locale) : options.locale;
16200 		}
16201 		if (options.sign) {
16202 			this.sign = options.sign;
16203 		}
16204 		if (typeof(options.sync) !== 'undefined') {
16205 			this.sync = options.sync;
16206 		}
16207 		if (options.loadParams) {
16208 			this.loadParams = options.loadParams;
16209 		}
16210 	}
16211 	
16212 	this.locale = this.locale || new ilib.Locale();
16213 	if (typeof(ilib.data.currency) === 'undefined') {
16214 		ilib.loadData({
16215 			name: "currency.json",
16216 			object: ilib.Currency, 
16217 			locale: "-",
16218 			sync: this.sync, 
16219 			loadParams: this.loadParams, 
16220 			callback: /** @type function(Object=):undefined */ ilib.bind(this, /** @type function() */ function(currency) {
16221 				ilib.data.currency = currency;
16222 				this._loadLocinfo(options && options.onLoad);
16223 			})
16224 		});
16225 	} else {
16226 		this._loadLocinfo(options && options.onLoad);
16227 	}
16228 };
16229 
16230 /**
16231  * Return an array of the ids for all ISO 4217 currencies that
16232  * this copy of ilib knows about.
16233  * 
16234  * @static
16235  * @return {Array.<string>} an array of currency ids that this copy of ilib knows about.
16236  */
16237 ilib.Currency.getAvailableCurrencies = function() {
16238 	var ret = [],
16239 		cur,
16240 		currencies = new ilib.ResBundle({
16241 			name: "currency"
16242 		}).getResObj();
16243 	
16244 	for (cur in currencies) {
16245 		if (cur && currencies[cur]) {
16246 			ret.push(cur);
16247 		}
16248 	}
16249 	
16250 	return ret;
16251 };
16252 
16253 ilib.Currency.prototype = {
16254 	/**
16255 	 * @private
16256 	 */
16257 	_loadLocinfo: function(onLoad) {
16258 		new ilib.LocaleInfo(this.locale, {
16259 			onLoad: ilib.bind(this, function (li) {
16260 				var currInfo;
16261 				
16262 				this.locinfo = li;
16263 		    	if (this.code) {
16264 		    		currInfo = ilib.data.currency[this.code];
16265 		    		if (!currInfo) {
16266 		    			throw "currency " + this.code + " is unknown";
16267 		    		}
16268 		    	} else if (this.sign) {
16269 		    		currInfo = ilib.data.currency[this.sign]; // maybe it is really a code...
16270 		    		if (typeof(currInfo) !== 'undefined') {
16271 		    			this.code = this.sign;
16272 		    		} else {
16273 		    			this.code = this.locinfo.getCurrency();
16274 		    			currInfo = ilib.data.currency[this.code];
16275 		    			if (currInfo.sign !== this.sign) {
16276 		    				// current locale does not use the sign, so search for it
16277 		    				for (var cur in ilib.data.currency) {
16278 		    					if (cur && ilib.data.currency[cur]) {
16279 		    						currInfo = ilib.data.currency[cur];
16280 		    						if (currInfo.sign === this.sign) {
16281 		    							// currency data is already ordered so that the currency with the
16282 		    							// largest circulation is at the beginning, so all we have to do
16283 		    							// is take the first one in the list that matches
16284 		    							this.code = cur;
16285 		    							break;
16286 		    						}
16287 		    					}
16288 		    				}
16289 		    			}
16290 		    		}
16291 		    	}
16292 		    	
16293 		    	if (!currInfo || !this.code) {
16294 		    		this.code = this.locinfo.getCurrency();
16295 		    		currInfo = ilib.data.currency[this.code];
16296 		    	}
16297 		    	
16298 		    	this.name = currInfo.name;
16299 		    	this.fractionDigits = currInfo.decimals;
16300 		    	this.sign = currInfo.sign;
16301 		    	
16302 				if (typeof(onLoad) === 'function') {
16303 					onLoad(this);
16304 				}
16305 			})
16306 		});
16307 	},
16308 	
16309 	/**
16310 	 * Return the ISO 4217 currency code for this instance.
16311 	 * @return {string} the ISO 4217 currency code for this instance
16312 	 */
16313 	getCode: function () {
16314 		return this.code;
16315 	},
16316 	
16317 	/**
16318 	 * Return the default number of fraction digits that is typically used
16319 	 * with this type of currency.
16320 	 * @return {number} the number of fraction digits for this currency
16321 	 */
16322 	getFractionDigits: function () {
16323 		return this.fractionDigits;
16324 	},
16325 	
16326 	/**
16327 	 * Return the sign commonly used to represent this currency.
16328 	 * @return {string} the sign commonly used to represent this currency
16329 	 */
16330 	getSign: function () {
16331 		return this.sign;
16332 	},
16333 	
16334 	/**
16335 	 * Return the name of the currency in English.
16336 	 * @return {string} the name of the currency in English
16337 	 */
16338 	getName: function () {
16339 		return this.name;
16340 	},
16341 	
16342 	/**
16343 	 * Return the locale for this currency. If the options to the constructor 
16344 	 * included a locale property in order to find the currency that is appropriate
16345 	 * for that locale, then the locale is returned here. If the options did not
16346 	 * include a locale, then this method returns undefined.
16347 	 * @return {ilib.Locale} the locale used in the constructor of this instance,
16348 	 * or undefined if no locale was given in the constructor
16349 	 */
16350 	getLocale: function () {
16351 		return this.locale;
16352 	}
16353 };
16354 
16355 /*
16356  * numfmt.js - Number formatter definition
16357  *
16358  * Copyright © 2012-2014, JEDLSoft
16359  *
16360  * Licensed under the Apache License, Version 2.0 (the "License");
16361  * you may not use this file except in compliance with the License.
16362  * You may obtain a copy of the License at
16363  *
16364  *     http://www.apache.org/licenses/LICENSE-2.0
16365  *
16366  * Unless required by applicable law or agreed to in writing, software
16367  * distributed under the License is distributed on an "AS IS" BASIS,
16368  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16369  *
16370  * See the License for the specific language governing permissions and
16371  * limitations under the License.
16372  */
16373 
16374 // !depends ilibglobal.js locale.js strings.js currency.js
16375 /*
16376 !depends 
16377 ilibglobal.js 
16378 locale.js
16379 localeinfo.js
16380 util/utils.js
16381 util/math.js
16382 currency.js
16383 strings.js
16384 util/jsutils.js
16385 */
16386 
16387 // !data localeinfo currency
16388 
16389 /**
16390  * @class
16391  * Create a new number formatter instance. Locales differ in the way that digits
16392  * in a formatted number are grouped, in the way the decimal character is represented,
16393  * etc. Use this formatter to get it right for any locale.<p>
16394  *
16395  * This formatter can format plain numbers, currency amounts, and percentage amounts.<p>
16396  *
16397  * As with all formatters, the recommended
16398  * practice is to create one formatter and use it multiple times to format various
16399  * numbers.<p>
16400  *
16401  * The options can contain any of the following properties:
16402  *
16403  * <ul>
16404  * <li><i>locale</i> - use the conventions of the specified locale when figuring out how to
16405  * format a number.
16406  * <li><i>type</i> - the type of this formatter. Valid values are "number", "currency", or
16407  * "percentage". If this property is not specified, the default is "number".
16408  * <li><i>currency</i> - the ISO 4217 3-letter currency code to use when the formatter type
16409  * is "currency". This property is required for currency formatting. If the type property
16410  * is "currency" and the currency property is not specified, the constructor will throw a
16411  * an exception.
16412  * <li><i>maxFractionDigits</i> - the maximum number of digits that should appear in the
16413  * formatted output after the decimal. A value of -1 means unlimited, and 0 means only print
16414  * the integral part of the number.
16415  * <li><i>minFractionDigits</i> - the minimum number of fractional digits that should
16416  * appear in the formatted output. If the number does not have enough fractional digits
16417  * to reach this minimum, the number will be zero-padded at the end to get to the limit.
16418  * If the type of the formatter is "currency" and this
16419  * property is not specified, then the minimum fraction digits is set to the normal number
16420  * of digits used with that currency, which is almost always 0, 2, or 3 digits.
16421  * <li><i>useNative</i> - the flag used to determaine whether to use the native script settings
16422  * for formatting the numbers .
16423  * <li><i>roundingMode</i> - When the maxFractionDigits or maxIntegerDigits is specified,
16424  * this property governs how the least significant digits are rounded to conform to that
16425  * maximum. The value of this property is a string with one of the following values:
16426  * <ul>
16427  *   <li><i>up</i> - round away from zero
16428  *   <li><i>down</i> - round towards zero. This has the effect of truncating the number
16429  *   <li><i>ceiling</i> - round towards positive infinity
16430  *   <li><i>floor</i> - round towards negative infinity
16431  *   <li><i>halfup</i> - round towards nearest neighbour. If equidistant, round up.
16432  *   <li><i>halfdown</i> - round towards nearest neighbour. If equidistant, round down.
16433  *   <li><i>halfeven</i> - round towards nearest neighbour. If equidistant, round towards the even neighbour
16434  *   <li><i>halfodd</i> - round towards nearest neighbour. If equidistant, round towards the odd neighbour
16435  * </ul>
16436  * When the type of the formatter is "currency" and the <i>roundingMode</i> property is not
16437  * set, then the standard legal rounding rules for the locale are followed. If the type
16438  * is "number" or "percentage" and the <i>roundingMode</i> property is not set, then the
16439  * default mode is "halfdown".</i>.
16440  *
16441  * <li><i>style</i> - When the type of this formatter is "currency", the currency amount
16442  * can be formatted in the following styles: "common" and "iso". The common style is the
16443  * one commonly used in every day writing where the currency unit is represented using a
16444  * symbol. eg. "$57.35" for fifty-seven dollars and thirty five cents. The iso style is
16445  * the international style where the currency unit is represented using the ISO 4217 code.
16446  * eg. "USD 57.35" for the same amount. The default is "common" style if the style is
16447  * not specified.<p>
16448  *
16449  * When the type of this formatter is "number", the style can be one of the following:
16450  * <ul>
16451  *   <li><i>standard - format a fully specified floating point number properly for the locale
16452  *   <li><i>scientific</i> - use scientific notation for all numbers. That is, 1 integral 
16453  *   digit, followed by a number of fractional digits, followed by an "e" which denotes 
16454  *   exponentiation, followed digits which give the power of 10 in the exponent. 
16455  *   <li><i>native</i> - format a floating point number using the native digits and 
16456  *   formatting symbols for the script of the locale. 
16457  *   <li><i>nogrouping</i> - format a floating point number without grouping digits for
16458  *   the integral portion of the number
16459  * </ul>
16460  * Note that if you specify a maximum number
16461  * of integral digits, the formatter with a standard style will give you standard
16462  * formatting for smaller numbers and scientific notation for larger numbers. The default
16463  * is standard style if this is not specified.
16464  *
16465  * <li><i>onLoad</i> - a callback function to call when the format data is fully
16466  * loaded. When the onLoad option is given, this class will attempt to
16467  * load any missing locale data using the ilib loader callback.
16468  * When the constructor is done (even if the data is already preassembled), the
16469  * onLoad function is called with the current instance as a parameter, so this
16470  * callback can be used with preassembled or dynamic loading or a mix of the two.
16471  *
16472  * <li>sync - tell whether to load any missing locale data synchronously or
16473  * asynchronously. If this option is given as "false", then the "onLoad"
16474  * callback must be given, as the instance returned from this constructor will
16475  * not be usable for a while.
16476  *
16477  * <li><i>loadParams</i> - an object containing parameters to pass to the
16478  * loader callback function when locale data is missing. The parameters are not
16479  * interpretted or modified in any way. They are simply passed along. The object
16480  * may contain any property/value pairs as long as the calling code is in
16481  * agreement with the loader callback function as to what those parameters mean.
16482  * </ul>
16483  * <p>
16484  *
16485  * Depends directive: !depends numfmt.js
16486  *
16487  * @constructor
16488  * @param {Object.<string,*>} options A set of options that govern how the formatter will behave
16489  */
16490 ilib.NumFmt = function (options) {
16491 	var sync = true;
16492 	this.locale = new ilib.Locale();
16493 	/** 
16494 	 * @private
16495 	 * @type {string} 
16496 	 */
16497 	this.type = "number";
16498 	var loadParams = undefined;
16499 
16500 	if (options) {
16501 		if (options.locale) {
16502 			this.locale = (typeof (options.locale) === 'string') ? new ilib.Locale(options.locale) : options.locale;
16503 		}
16504 
16505 		if (options.type) {
16506 			if (options.type === 'number' ||
16507 				options.type === 'currency' ||
16508 				options.type === 'percentage') {
16509 				this.type = options.type;
16510 			}
16511 		}
16512 
16513 		if (options.currency) {
16514 			/** 
16515 			 * @private 
16516 			 * @type {string} 
16517 			 */
16518 			this.currency = options.currency;
16519 		}
16520 
16521 		if (typeof (options.maxFractionDigits) === 'number') {
16522 			/** 
16523 			 * @private 
16524 			 * @type {number|undefined} 
16525 			 */
16526 			this.maxFractionDigits = this._toPrimitive(options.maxFractionDigits);
16527 		}
16528 		if (typeof (options.minFractionDigits) === 'number') {
16529 			/** 
16530 			 * @private 
16531 			 * @type {number|undefined} 
16532 			 */
16533 			this.minFractionDigits = this._toPrimitive(options.minFractionDigits);
16534 			// enforce the limits to avoid JS exceptions
16535 			if (this.minFractionDigits < 0) {
16536 				this.minFractionDigits = 0;
16537 			}
16538 			if (this.minFractionDigits > 20) {
16539 				this.minFractionDigits = 20;
16540 			}
16541 		}
16542 		if (options.style) {
16543 			/** 
16544 			 * @private 
16545 			 * @type {string} 
16546 			 */
16547 			this.style = options.style;
16548 		}
16549 		if (typeof(options.useNative) === 'boolean') {
16550 			/** 
16551 			 * @private 
16552 			 * @type {boolean} 
16553 			 * */
16554 			this.useNative = options.useNative;
16555 		}
16556 		/** 
16557 		 * @private 
16558 		 * @type {string} 
16559 		 */
16560 		this.roundingMode = options.roundingMode;
16561 
16562 		if (typeof (options.sync) !== 'undefined') {
16563 			/** @type {boolean} */
16564 			sync = (options.sync == true);
16565 		}
16566 		
16567 		loadParams = options.loadParams;
16568 	}
16569 
16570 	/** 
16571 	 * @private 
16572 	 * @type {ilib.LocaleInfo|undefined} 
16573 	 */
16574 	this.localeInfo = undefined;
16575 	
16576 	new ilib.LocaleInfo(this.locale, {
16577 		sync: sync,
16578 		loadParams: loadParams,
16579 		onLoad: ilib.bind(this, function (li) {
16580 			/** 
16581 			 * @private 
16582 			 * @type {ilib.LocaleInfo|undefined} 
16583 			 */
16584 			this.localeInfo = li;
16585 
16586 			if (this.type === "number") {
16587 				this.templateNegative = new ilib.String(this.localeInfo.getNegativeNumberFormat() || "-{n}");
16588 			} else if (this.type === "currency") {
16589 				var templates;
16590 
16591 				if (!this.currency || typeof (this.currency) != 'string') {
16592 					throw "A currency property is required in the options to the number formatter constructor when the type property is set to currency.";
16593 				}
16594 
16595 				new ilib.Currency({
16596 					locale: this.locale,
16597 					code: this.currency,
16598 					sync: sync,
16599 					loadParams: loadParams,
16600 					onLoad: ilib.bind(this, function (cur) {
16601 						this.currencyInfo = cur;
16602 						if (this.style !== "common" && this.style !== "iso") {
16603 							this.style = "common";
16604 						}
16605 						
16606 						if (typeof(this.maxFractionDigits) !== 'number' && typeof(this.minFractionDigits) !== 'number') {
16607 							this.minFractionDigits = this.maxFractionDigits = this.currencyInfo.getFractionDigits();
16608 						}
16609 
16610 						templates = this.localeInfo.getCurrencyFormats();
16611 						this.template = new ilib.String(templates[this.style] || templates.common);
16612 						this.templateNegative = new ilib.String(templates[this.style + "Negative"] || templates["commonNegative"]);
16613 						this.sign = (this.style === "iso") ? this.currencyInfo.getCode() : this.currencyInfo.getSign();
16614 						
16615 						if (!this.roundingMode) {
16616 							this.roundingMode = this.currencyInfo && this.currencyInfo.roundingMode;
16617 						}
16618 
16619 						this._init();
16620 
16621 						if (options && typeof (options.onLoad) === 'function') {
16622 							options.onLoad(this);
16623 						}
16624 					})
16625 				});
16626 				return;
16627 			} else if (this.type === "percentage") {
16628 				this.template =  new ilib.String(this.localeInfo.getPercentageFormat() || "{n}%");
16629 				this.templateNegative = new ilib.String(this.localeInfo.getNegativePercentageFormat() || this.localeInfo.getNegativeNumberFormat() + "%");
16630 			}
16631 
16632 			this._init();
16633 
16634 			if (options && typeof (options.onLoad) === 'function') {
16635 				options.onLoad(this);
16636 			}
16637 		})
16638 	});
16639 };
16640 
16641 /**
16642  * Return an array of available locales that this formatter can format
16643  * @static
16644  * @return {Array.<ilib.Locale>|undefined} an array of available locales
16645  */
16646 ilib.NumFmt.getAvailableLocales = function () {
16647 	return undefined;
16648 };
16649 
16650 /**
16651  * @private
16652  * @const
16653  * @type string
16654  */
16655 ilib.NumFmt.zeros = "0000000000000000000000000000000000000000000000000000000000000000000000";
16656 
16657 ilib.NumFmt.prototype = {
16658 	/**
16659 	 * Return true if this formatter uses native digits to format the number. If the useNative
16660 	 * option is given to the constructor, then this flag will be honoured. If the useNative
16661 	 * option is not given to the constructor, this this formatter will use native digits if
16662 	 * the locale typically uses native digits.
16663 	 * 
16664 	 *  @return {boolean} true if this formatter will format with native digits, false otherwise
16665 	 */
16666 	getUseNative: function() {
16667 		if (typeof(this.useNative) === "boolean") {
16668 			return this.useNative;
16669 		} 
16670 		return (this.localeInfo.getDigitsStyle() === "native");
16671 	},
16672 	
16673 	/**
16674 	 * @private
16675 	 */
16676 	_init: function () {
16677 		if (this.maxFractionDigits < this.minFractionDigits) {
16678 			this.minFractionDigits = this.maxFractionDigits;
16679 		}
16680 
16681 		if (!this.roundingMode) {
16682 			this.roundingMode = this.localeInfo.getRoundingMode();
16683 		}
16684 
16685 		if (!this.roundingMode) {
16686 			this.roundingMode = "halfdown";
16687 		}
16688 
16689 		// set up the function, so we only have to figure it out once
16690 		// and not every time we do format()
16691 		this.round = ilib._roundFnc[this.roundingMode];
16692 		if (!this.round) {
16693 			this.roundingMode = "halfdown";
16694 			this.round = ilib._roundFnc[this.roundingMode];
16695 		}
16696 		
16697 		if (this.style === "nogrouping") {
16698 			this.prigroupSize = this.secgroupSize = 0;
16699 		} else {
16700 			this.prigroupSize = this.localeInfo.getPrimaryGroupingDigits();
16701 			this.secgroupSize = this.localeInfo.getSecondaryGroupingDigits();
16702 			this.groupingSeparator = this.getUseNative() ? this.localeInfo.getNativeGroupingSeparator() : this.localeInfo.getGroupingSeparator();
16703 		} 
16704 		this.decimalSeparator = this.getUseNative() ? this.localeInfo.getNativeDecimalSeparator() : this.localeInfo.getDecimalSeparator();
16705 		
16706 		if (this.getUseNative()) {
16707 			var nd = this.localeInfo.getNativeDigits() || this.localeInfo.getDigits();
16708 			if (nd) {
16709 				this.digits = nd.split("");
16710 			}
16711 		}
16712 		
16713 		this.exponentSymbol = this.localeInfo.getExponential() || "e";
16714 	},
16715 
16716 	/*
16717 	 * @private
16718 	 */
16719 	_pad: function (str, length, left) {
16720 		return (str.length >= length) ?
16721 			str :
16722 			(left ?
16723 			ilib.NumFmt.zeros.substring(0, length - str.length) + str :
16724 			str + ilib.NumFmt.zeros.substring(0, length - str.length));
16725 	},
16726 
16727 	/**
16728 	 * @private
16729 	 * @param {Number|ilib.Number|string|number} num object, string, or number to convert to a primitive number
16730 	 * @return {number} the primitive number equivalent of the argument
16731 	 */
16732 	_toPrimitive: function (num) {
16733 		var n = 0;
16734 
16735 		switch (typeof (num)) {
16736 		case 'number':
16737 			n = num;
16738 			break;
16739 		case 'string':
16740 			n = parseFloat(num);
16741 			break;
16742 		case 'object':
16743 			// Number.valueOf() is incorrectly documented as being of type "string" rather than "number", so coerse 
16744 			// the type here to shut the type checker up
16745 			n = /** @type {number} */ num.valueOf();
16746 			break;
16747 		}
16748 
16749 		return n;
16750 	},
16751 
16752 	/**
16753 	 * Format the number using scientific notation as a positive number. Negative
16754 	 * formatting to be applied later.
16755 	 * @private
16756 	 * @param {number} num the number to format
16757 	 * @return {string} the formatted number
16758 	 */
16759 	_formatScientific: function (num) {
16760 		var n = new Number(num);
16761 		var formatted;
16762 		
16763 		var factor,
16764 			str = n.toExponential(),
16765 			parts = str.split("e"),
16766 			significant = parts[0],
16767 			exponent = parts[1],
16768 			numparts,
16769 			integral,
16770 			fraction;
16771 
16772 		if (this.maxFractionDigits > 0) {
16773 			// if there is a max fraction digits setting, round the fraction to 
16774 			// the right length first by dividing or multiplying by powers of 10. 
16775 			// manipulate the fraction digits so as to
16776 			// avoid the rounding errors of floating point numbers
16777 			factor = Math.pow(10, this.maxFractionDigits);
16778 			significant = this.round(significant * factor) / factor;
16779 		}
16780 		numparts = ("" + significant).split(".");
16781 		integral = numparts[0];
16782 		fraction = numparts[1];
16783 		
16784 		if (typeof(this.maxFractionDigits) !== 'undefined') {
16785 			fraction = fraction.substring(0, this.maxFractionDigits);
16786 		}
16787 		if (typeof(this.minFractionDigits) !== 'undefined') {
16788 			fraction = this._pad(fraction || "", this.minFractionDigits, false);
16789 		}
16790 		formatted = integral;
16791 		if (fraction.length) {
16792 			formatted += this.decimalSeparator + fraction;	
16793 		} 
16794 		formatted += this.exponentSymbol + exponent;
16795 		return formatted;
16796 	},
16797 
16798 	/**
16799 	 * Formats the number as a positive number. Negative formatting to be applied later.
16800 	 * @private
16801 	 * @param {number} num the number to format
16802 	 * @return {string} the formatted number
16803 	 */
16804 	_formatStandard: function (num) {
16805 		var i;
16806 		var k;
16807 		
16808 		if (typeof(this.maxFractionDigits) !== 'undefined' && this.maxFractionDigits > -1) {
16809 			var factor = Math.pow(10, this.maxFractionDigits);
16810 			num = this.round(num * factor) / factor;
16811 		}
16812 
16813 		num = Math.abs(num);
16814 
16815 		var parts = ("" + num).split("."),
16816 			integral = parts[0],
16817 			fraction = parts[1],
16818 			cycle,
16819 			formatted;
16820 		
16821 		integral = integral.toString();
16822 
16823 		if (this.minFractionDigits > 0) {
16824 			fraction = this._pad(fraction || "", this.minFractionDigits, false);
16825 		}
16826 
16827 		if (this.secgroupSize > 0) {
16828 			if (integral.length > this.prigroupSize) {
16829 				var size1 = this.prigroupSize;
16830 				var size2 = integral.length;
16831 				var size3 = size2 - size1;
16832 				integral = integral.slice(0, size3) + this.groupingSeparator + integral.slice(size3);
16833 				var num_sec = integral.substring(0, integral.indexOf(this.groupingSeparator));
16834 				k = num_sec.length;
16835 				while (k > this.secgroupSize) {
16836 					var secsize1 = this.secgroupSize;
16837 					var secsize2 = num_sec.length;
16838 					var secsize3 = secsize2 - secsize1;
16839 					integral = integral.slice(0, secsize3) + this.groupingSeparator + integral.slice(secsize3);
16840 					num_sec = integral.substring(0, integral.indexOf(this.groupingSeparator));
16841 					k = num_sec.length;
16842 				}
16843 			}
16844 
16845 			formatted = integral;
16846 		} else if (this.prigroupSize !== 0) {
16847 			cycle = ilib.mod(integral.length - 1, this.prigroupSize);
16848 
16849 			formatted = "";
16850 
16851 			for (i = 0; i < integral.length - 1; i++) {
16852 				formatted += integral.charAt(i);
16853 				if (cycle === 0) {
16854 					formatted += this.groupingSeparator;
16855 				}
16856 				cycle = ilib.mod(cycle - 1, this.prigroupSize);
16857 			}
16858 			formatted += integral.charAt(integral.length - 1);
16859 		} else {
16860 			formatted = integral;
16861 		}
16862 
16863 		if (fraction && (typeof(this.maxFractionDigits) === 'undefined' || this.maxFractionDigits > 0)) {
16864 			formatted += this.decimalSeparator;
16865 			formatted += fraction;
16866 		}
16867 		
16868 		if (this.digits) {
16869 			formatted = ilib.mapString(formatted, this.digits);
16870 		}
16871 		
16872 		return formatted;
16873 	},
16874 
16875 	/**
16876 	 * Format a number according to the settings of this number formatter instance.
16877 	 * @param num {number|string|Number|ilib.Number} a floating point number to format
16878 	 * @return {string} a string containing the formatted number
16879 	 */
16880 	format: function (num) {
16881 		var formatted, n;
16882 
16883 		if (typeof (num) === 'undefined') {
16884 			return "";
16885 		}
16886 
16887 		// convert to a real primitive number type
16888 		n = this._toPrimitive(num);
16889 
16890 		if (this.type === "number") {
16891 			formatted = (this.style === "scientific") ?
16892 				this._formatScientific(n) :
16893 				this._formatStandard(n);
16894 
16895 			if (num < 0) {
16896 				formatted = this.templateNegative.format({n: formatted});
16897 			}
16898 		} else {
16899 			formatted = this._formatStandard(n);
16900 			var template = (n < 0) ? this.templateNegative : this.template;
16901 			formatted = template.format({
16902 				n: formatted,
16903 				s: this.sign
16904 			});
16905 		}
16906 
16907 		return formatted;
16908 	},
16909 
16910 	/**
16911 	 * Return the type of formatter. Valid values are "number", "currency", and
16912 	 * "percentage".
16913 	 *
16914 	 * @return {string} the type of formatter
16915 	 */
16916 	getType: function () {
16917 		return this.type;
16918 	},
16919 
16920 	/**
16921 	 * Return the locale for this formatter instance.
16922 	 * @return {ilib.Locale} the locale instance for this formatter
16923 	 */
16924 	getLocale: function () {
16925 		return this.locale;
16926 	},
16927 
16928 	/**
16929 	 * Returns true if this formatter groups together digits in the integral
16930 	 * portion of a number, based on the options set up in the constructor. In
16931 	 * most western European cultures, this means separating every 3 digits
16932 	 * of the integral portion of a number with a particular character.
16933 	 *
16934 	 * @return {boolean} true if this formatter groups digits in the integral
16935 	 * portion of the number
16936 	 */
16937 	isGroupingUsed: function () {
16938 		return (this.groupingSeparator !== 'undefined' && this.groupingSeparator.length > 0);
16939 	},
16940 
16941 	/**
16942 	 * Returns the maximum fraction digits set up in the constructor.
16943 	 *
16944 	 * @return {number} the maximum number of fractional digits this
16945 	 * formatter will format, or -1 for no maximum
16946 	 */
16947 	getMaxFractionDigits: function () {
16948 		return typeof (this.maxFractionDigits) !== 'undefined' ? this.maxFractionDigits : -1;
16949 	},
16950 
16951 	/**
16952 	 * Returns the minimum fraction digits set up in the constructor. If
16953 	 * the formatter has the type "currency", then the minimum fraction
16954 	 * digits is the amount of digits that is standard for the currency
16955 	 * in question unless overridden in the options to the constructor.
16956 	 *
16957 	 * @return {number} the minimum number of fractional digits this
16958 	 * formatter will format, or -1 for no minimum
16959 	 */
16960 	getMinFractionDigits: function () {
16961 		return typeof (this.minFractionDigits) !== 'undefined' ? this.minFractionDigits : -1;
16962 	},
16963 
16964 	/**
16965 	 * Returns the ISO 4217 code for the currency that this formatter formats.
16966 	 * IF the typeof this formatter is not "currency", then this method will
16967 	 * return undefined.
16968 	 *
16969 	 * @return {string} the ISO 4217 code for the currency that this formatter
16970 	 * formats, or undefined if this not a currency formatter
16971 	 */
16972 	getCurrency: function () {
16973 		return this.currencyInfo && this.currencyInfo.getCode();
16974 	},
16975 
16976 	/**
16977 	 * Returns the rounding mode set up in the constructor. The rounding mode
16978 	 * controls how numbers are rounded when the integral or fraction digits
16979 	 * of a number are limited.
16980 	 *
16981 	 * @return {string} the name of the rounding mode used in this formatter
16982 	 */
16983 	getRoundingMode: function () {
16984 		return this.roundingMode;
16985 	},
16986 
16987 	/**
16988 	 * If this formatter is a currency formatter, then the style determines how the
16989 	 * currency is denoted in the formatted output. This method returns the style
16990 	 * that this formatter will produce. (See the constructor comment for more about
16991 	 * the styles.)
16992 	 * @return {string} the name of the style this formatter will use to format
16993 	 * currency amounts, or "undefined" if this formatter is not a currency formatter
16994 	 */
16995 	getStyle: function () {
16996 		return this.style;
16997 	}
16998 };
16999 
17000 /*
17001  * durfmt.js - Date formatter definition
17002  * 
17003  * Copyright © 2012-2014, JEDLSoft
17004  *
17005  * Licensed under the Apache License, Version 2.0 (the "License");
17006  * you may not use this file except in compliance with the License.
17007  * You may obtain a copy of the License at
17008  *
17009  *     http://www.apache.org/licenses/LICENSE-2.0
17010  *
17011  * Unless required by applicable law or agreed to in writing, software
17012  * distributed under the License is distributed on an "AS IS" BASIS,
17013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17014  *
17015  * See the License for the specific language governing permissions and
17016  * limitations under the License.
17017  */
17018 
17019 /*
17020 !depends 
17021 ilibglobal.js 
17022 locale.js 
17023 date.js 
17024 strings.js 
17025 resources.js 
17026 localeinfo.js
17027 util/jsutils.js
17028 */
17029 
17030 // !data dateformats sysres
17031 // !resbundle sysres
17032 
17033 /**
17034  * @class
17035  * Create a new duration formatter instance. The duration formatter is immutable once
17036  * it is created, but can format as many different durations as needed with the same
17037  * options. Create different duration formatter instances for different purposes
17038  * and then keep them cached for use later if you have more than one duration to
17039  * format.<p>
17040  * 
17041  * Duration formatters format lengths of time. The duration formatter is meant to format 
17042  * durations of such things as the length of a song or a movie or a meeting, or the 
17043  * current position in that song or movie while playing it. If you wish to format a 
17044  * period of time that has a specific start and end date/time, then use a
17045  * [ilib.DateRngFmt] instance instead and call its format method.<p>
17046  *  
17047  * The options may contain any of the following properties:
17048  * 
17049  * <ul>
17050  * <li><i>locale</i> - locale to use when formatting the duration. If the locale is
17051  * not specified, then the default locale of the app or web page will be used.
17052  * 
17053  * <li><i>length</i> - Specify the length of the format to use. The length is the approximate size of the 
17054  * formatted string.
17055  * 
17056  * <ul>
17057  * <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
17058  * <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
17059  * <li><i>long</i> - use a long representation of the duration. This is a fully specified format, but some of the textual 
17060  * parts may still be abbreviated. eg. 1 yr 1 mo 1 wk 1 day 1 hr 1 min 1 sec
17061  * <li><i>full</i> - use a full representation of the duration. This is a fully specified format where all the textual 
17062  * parts are spelled out completely. eg. 1 year, 1 month, 1 week, 1 day, 1 hour, 1 minute and 1 second
17063  * </ul>
17064  * 
17065  * <li><i>style<i> - whether hours, minutes, and seconds should be formatted as a text string
17066  * or as a regular time as on a clock. eg. text is "1 hour, 15 minutes", whereas clock is "1:15:00". Valid
17067  * values for this property are "text" or "clock". Default if this property is not specified
17068  * is "text".
17069  * 
17070  *<li><i>useNative</i> - the flag used to determaine whether to use the native script settings 
17071  * for formatting the numbers .
17072  * 
17073  * <li><i>onLoad</i> - a callback function to call when the format data is fully 
17074  * loaded. When the onLoad option is given, this class will attempt to
17075  * load any missing locale data using the ilib loader callback.
17076  * When the constructor is done (even if the data is already preassembled), the 
17077  * onLoad function is called with the current instance as a parameter, so this
17078  * callback can be used with preassembled or dynamic loading or a mix of the two. 
17079  * 
17080  * <li>sync - tell whether to load any missing locale data synchronously or 
17081  * asynchronously. If this option is given as "false", then the "onLoad"
17082  * callback must be given, as the instance returned from this constructor will
17083  * not be usable for a while.
17084  *  
17085  * <li><i>loadParams</i> - an object containing parameters to pass to the 
17086  * loader callback function when locale data is missing. The parameters are not
17087  * interpretted or modified in any way. They are simply passed along. The object 
17088  * may contain any property/value pairs as long as the calling code is in
17089  * agreement with the loader callback function as to what those parameters mean.
17090  * </ul>
17091  * <p>
17092  * 
17093  * Depends directive: !depends durfmt.js
17094  * 
17095  * @constructor
17096  * @param {?Object} options options governing the way this date formatter instance works
17097  */
17098 ilib.DurFmt = function(options) {
17099 	var sync = true;
17100 	var loadParams = undefined;
17101 	
17102 	this.locale = new ilib.Locale();
17103 	this.length = "short";
17104 	this.style = "text";
17105 	
17106 	if (options) {
17107 		if (options.locale) {
17108 			this.locale = (typeof(options.locale) === 'string') ? new ilib.Locale(options.locale) : options.locale;
17109 		}
17110 		
17111 		if (options.length) {
17112 			if (options.length === 'short' ||
17113 				options.length === 'medium' ||
17114 				options.length === 'long' ||
17115 				options.length === 'full') {
17116 				this.length = options.length;
17117 			}
17118 		}
17119 		
17120 		if (options.style) {
17121 			if (options.style === 'text' || options.style === 'clock') {
17122 				this.style = options.style;
17123 			}
17124 		}
17125 		
17126 		if (typeof(options.sync) !== 'undefined') {
17127 			sync = (options.sync == true);
17128 		}
17129 		
17130 		if (typeof(options.useNative) === 'boolean') {
17131 			this.useNative = options.useNative;
17132 		}
17133 		
17134 		loadParams = options.loadParams;
17135 	}
17136 	
17137 	new ilib.ResBundle({
17138 		locale: this.locale,
17139 		name: "sysres",
17140 		sync: sync,
17141 		loadParams: loadParams,
17142 		onLoad: ilib.bind(this, function (sysres) {
17143 			switch (this.length) {
17144 				case 'short':
17145 					this.components = {
17146 						year: sysres.getString("#{num}y"),
17147 						month: sysres.getString("#{num}m", "durationShortMonths"),
17148 						week: sysres.getString("#{num}w"),
17149 						day: sysres.getString("#{num}d"),
17150 						hour: sysres.getString("#{num}h"),
17151 						minute: sysres.getString("#{num}m", "durationShortMinutes"),
17152 						second: sysres.getString("#{num}s"),
17153 						millisecond: sysres.getString("#{num}m", "durationShortMillis"),
17154 						separator: sysres.getString(" ", "separatorShort"),
17155 						finalSeparator: "" // not used at this length
17156 					};
17157 					break;
17158 					
17159 				case 'medium':
17160 					this.components = {
17161 						year: sysres.getString("1#1 yr|#{num} yrs", "durationMediumYears"),
17162 						month: sysres.getString("1#1 mo|#{num} mos"),
17163 						week: sysres.getString("1#1 wk|#{num} wks", "durationMediumWeeks"),
17164 						day: sysres.getString("1#1 dy|#{num} dys"),
17165 						hour: sysres.getString("1#1 hr|#{num} hrs", "durationMediumHours"),
17166 						minute: sysres.getString("1#1 mi|#{num} min"),
17167 						second: sysres.getString("1#1 se|#{num} sec"),
17168 						millisecond: sysres.getString("#{num} ms"),
17169 						separator: sysres.getString(" ", "separatorMedium"),
17170 						finalSeparator: "" // not used at this length
17171 					};
17172 					break;
17173 					
17174 				case 'long':
17175 					this.components = {
17176 						year: sysres.getString("1#1 yr|#{num} yrs"),
17177 						month: sysres.getString("1#1 mon|#{num} mons"),
17178 						week: sysres.getString("1#1 wk|#{num} wks"),
17179 						day: sysres.getString("1#1 day|#{num} days", "durationLongDays"),
17180 						hour: sysres.getString("1#1 hr|#{num} hrs"),
17181 						minute: sysres.getString("1#1 min|#{num} min"),
17182 						second: sysres.getString("1#1 sec|#{num} sec"),
17183 						millisecond: sysres.getString("#{num} ms"),
17184 						separator: sysres.getString(", ", "separatorLong"),
17185 						finalSeparator: "" // not used at this length
17186 					};
17187 					break;
17188 					
17189 				case 'full':
17190 					this.components = {
17191 						year: sysres.getString("1#1 year|#{num} years"),
17192 						month: sysres.getString("1#1 month|#{num} months"),
17193 						week: sysres.getString("1#1 week|#{num} weeks"),
17194 						day: sysres.getString("1#1 day|#{num} days"),
17195 						hour: sysres.getString("1#1 hour|#{num} hours"),
17196 						minute: sysres.getString("1#1 minute|#{num} minutes"),
17197 						second: sysres.getString("1#1 second|#{num} seconds"),
17198 						millisecond: sysres.getString("1#1 millisecond|#{num} milliseconds"),
17199 						separator: sysres.getString(", ", "separatorFull"),
17200 						finalSeparator: sysres.getString(" and ", "finalSeparatorFull")
17201 					};
17202 					break;
17203 			}
17204 			
17205 			if (this.style === 'clock') {
17206 				new ilib.DateFmt({
17207 					locale: this.locale,
17208 					calendar: "gregorian",
17209 					type: "time",
17210 					time: "ms",
17211 					sync: sync,
17212 					loadParams: loadParams,
17213 					useNative: this.useNative,
17214 					onLoad: ilib.bind(this, function (fmtMS) {
17215 						this.timeFmtMS = fmtMS;
17216 						new ilib.DateFmt({
17217 							locale: this.locale,
17218 							calendar: "gregorian",
17219 							type: "time",
17220 							time: "hm",
17221 							sync: sync,
17222 							loadParams: loadParams,
17223 							useNative: this.useNative,
17224 							onLoad: ilib.bind(this, function (fmtHM) {
17225 								this.timeFmtHM = fmtHM;		
17226 								new ilib.DateFmt({
17227 									locale: this.locale,
17228 									calendar: "gregorian",
17229 									type: "time",
17230 									time: "hms",
17231 									sync: sync,
17232 									loadParams: loadParams,
17233 									useNative: this.useNative,
17234 									onLoad: ilib.bind(this, function (fmtHMS) {
17235 										this.timeFmtHMS = fmtHMS;		
17236 
17237 										// munge with the template to make sure that the hours are not formatted mod 12
17238 										this.timeFmtHM.template = this.timeFmtHM.template.replace(/hh?/, 'H');
17239 										this.timeFmtHM.templateArr = this.timeFmtHM._tokenize(this.timeFmtHM.template);
17240 										this.timeFmtHMS.template = this.timeFmtHMS.template.replace(/hh?/, 'H');
17241 										this.timeFmtHMS.templateArr = this.timeFmtHMS._tokenize(this.timeFmtHMS.template);
17242 										
17243 										this._init(this.timeFmtHM.locinfo, options && options.onLoad);
17244 									})
17245 								});
17246 							})
17247 						});
17248 					})
17249 				});
17250 				return;
17251 			}
17252 
17253 			new ilib.LocaleInfo(this.locale, {
17254 				sync: sync,
17255 				loadParams: loadParams,
17256 				onLoad: ilib.bind(this, function (li) {
17257 					this._init(li, options && options.onLoad);
17258 				})
17259 			});
17260 		})
17261 	});
17262 };
17263 
17264 /**
17265  * @private
17266  * @static
17267  */
17268 ilib.DurFmt.complist = {
17269 	"text": ["year", "month", "week", "day", "hour", "minute", "second", "millisecond"],
17270 	"clock": ["year", "month", "week", "day"]
17271 };
17272 
17273 /**
17274  * @private
17275  */
17276 ilib.DurFmt.prototype._mapDigits = function(str) {
17277 	if (this.useNative && this.digits) {
17278 		return ilib.mapString(str.toString(), this.digits);
17279 	}
17280 	return str;
17281 };
17282 
17283 /**
17284  * @private
17285  * @param {ilib.LocaleInfo} locinfo
17286  * @param {function(ilib.DurFmt)|undefined} onLoad
17287  */
17288 ilib.DurFmt.prototype._init = function(locinfo, onLoad) {
17289 	var digits;
17290 	if (typeof(this.useNative) === 'boolean') {
17291 		// if the caller explicitly said to use native or not, honour that despite what the locale data says...
17292 		if (this.useNative) {
17293 			digits = locinfo.getNativeDigits();
17294 			if (digits) {
17295 				this.digits = digits;
17296 			}
17297 		}
17298 	} else if (locinfo.getDigitsStyle() === "native") {
17299 		// else if the locale usually uses native digits, then use them 
17300 		digits = locinfo.getNativeDigits();
17301 		if (digits) {
17302 			this.useNative = true;
17303 			this.digits = digits;
17304 		}
17305 	} // else use western digits always
17306 
17307 	if (typeof(onLoad) === 'function') {
17308 		onLoad(this);
17309 	}
17310 };
17311 
17312 /**
17313  * Format a duration according to the format template of this formatter instance.<p>
17314  * 
17315  * The components parameter should be an object that contains any or all of these 
17316  * numeric properties:
17317  * 
17318  * <ul>
17319  * <li>year
17320  * <li>month
17321  * <li>week
17322  * <li>day
17323  * <li>hour
17324  * <li>minute
17325  * <li>second
17326  * </ul>
17327  * <p>
17328  *
17329  * When a property is left out of the components parameter or has a value of 0, it will not
17330  * be formatted into the output string, except for times that include 0 minutes and 0 seconds.
17331  * 
17332  * This formatter will not ensure that numbers for each component property is within the
17333  * valid range for that component. This allows you to format durations that are longer
17334  * than normal range. For example, you could format a duration has being "33 hours" rather
17335  * than "1 day, 9 hours".
17336  * 
17337  * @param {Object} components date/time components to be formatted into a duration string
17338  * @return {ilib.String} a string with the duration formatted according to the style and 
17339  * locale set up for this formatter instance. If the components parameter is empty or 
17340  * undefined, an empty string is returned.
17341  */
17342 ilib.DurFmt.prototype.format = function (components) {
17343 	var i, list, temp, fmt, secondlast = true, str = "";
17344 	
17345 	list = ilib.DurFmt.complist[this.style];
17346 	//for (i = 0; i < list.length; i++) {
17347 	for (i = list.length-1; i >= 0; i--) {
17348 		//console.log("Now dealing with " + list[i]);
17349 		if (typeof(components[list[i]]) !== 'undefined' && components[list[i]] != 0) {
17350 			if (str.length > 0) {
17351 				str = ((this.length === 'full' && secondlast) ? this.components.finalSeparator : this.components.separator) + str;
17352 				secondlast = false;
17353 			}
17354 			str = this.components[list[i]].formatChoice(components[list[i]], {num: this._mapDigits(components[list[i]])}) + str;
17355 		}
17356 	}
17357 
17358 	if (this.style === 'clock') {
17359 		if (typeof(components.hour) !== 'undefined') {
17360 			fmt = (typeof(components.second) !== 'undefined') ? this.timeFmtHMS : this.timeFmtHM;
17361 		} else {
17362 			fmt = this.timeFmtMS;
17363 		}
17364 				
17365 		if (str.length > 0) {
17366 			str += this.components.separator;
17367 		}
17368 		str += fmt._formatTemplate(components, fmt.templateArr);
17369 	}
17370 	
17371 	return new ilib.String(str);
17372 };
17373 
17374 /**
17375  * Return the locale that was used to construct this duration formatter object. If the
17376  * locale was not given as parameter to the constructor, this method returns the default
17377  * locale of the system.
17378  * 
17379  * @return {ilib.Locale} locale that this duration formatter was constructed with
17380  */
17381 ilib.DurFmt.prototype.getLocale = function () {
17382 	return this.locale;
17383 };
17384 
17385 /**
17386  * Return the length that was used to construct this duration formatter object. If the
17387  * length was not given as parameter to the constructor, this method returns the default
17388  * length. Valid values are "short", "medium", "long", and "full".
17389  * 
17390  * @return {string} length that this duration formatter was constructed with
17391  */
17392 ilib.DurFmt.prototype.getLength = function () {
17393 	return this.length;
17394 };
17395 
17396 /**
17397  * Return the style that was used to construct this duration formatter object. Returns
17398  * one of "text" or "clock".
17399  * 
17400  * @return {string} style that this duration formatter was constructed with
17401  */
17402 ilib.DurFmt.prototype.getStyle = function () {
17403 	return this.style;
17404 };
17405 
17406 /*
17407  * ctype.islpha.js - Character type is alphabetic
17408  * 
17409  * Copyright © 2012-2013, JEDLSoft
17410  *
17411  * Licensed under the Apache License, Version 2.0 (the "License");
17412  * you may not use this file except in compliance with the License.
17413  * You may obtain a copy of the License at
17414  *
17415  *     http://www.apache.org/licenses/LICENSE-2.0
17416  *
17417  * Unless required by applicable law or agreed to in writing, software
17418  * distributed under the License is distributed on an "AS IS" BASIS,
17419  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17420  *
17421  * See the License for the specific language governing permissions and
17422  * limitations under the License.
17423  */
17424 
17425 // !depends ctype.js
17426 
17427 // !data ctype_l
17428 
17429 /**
17430  * Return whether or not the first character is alphabetic.<p>
17431  * 
17432  * Depends directive: !depends ctype.isalnum.js
17433  * 
17434  * @param {string|ilib.String|number} ch character or code point to examine
17435  * @return {boolean} true if the first character is alphabetic.
17436  */
17437 ilib.CType.isAlpha = function (ch) {
17438 	var num;
17439 	switch (typeof(ch)) {
17440 		case 'number':
17441 			num = ch;
17442 			break;
17443 		case 'string':
17444 			num = ilib.String.toCodePoint(ch, 0);
17445 			break;
17446 		case 'undefined':
17447 			return false;
17448 		default:
17449 			num = ch._toCodePoint(0);
17450 			break;
17451 	}
17452 	return ilib.CType._inRange(num, 'Lu', ilib.data.ctype_l) ||
17453 		ilib.CType._inRange(num, 'Ll', ilib.data.ctype_l) ||
17454 		ilib.CType._inRange(num, 'Lt', ilib.data.ctype_l) ||
17455 		ilib.CType._inRange(num, 'Lm', ilib.data.ctype_l) ||
17456 		ilib.CType._inRange(num, 'Lo', ilib.data.ctype_l);
17457 };
17458 
17459 /**
17460  * @protected
17461  * @param {boolean} sync
17462  * @param {Object} loadParams
17463  * @param {function(*)|undefined} onLoad
17464  */
17465 ilib.CType.isAlpha._init = function (sync, loadParams, onLoad) {
17466 	ilib.CType._load("ctype_l", sync, loadParams, onLoad);
17467 };
17468 
17469 
17470 
17471 /*
17472  * ctype.isalnum.js - Character type alphanumeric
17473  * 
17474  * Copyright © 2012-2013, JEDLSoft
17475  *
17476  * Licensed under the Apache License, Version 2.0 (the "License");
17477  * you may not use this file except in compliance with the License.
17478  * You may obtain a copy of the License at
17479  *
17480  *     http://www.apache.org/licenses/LICENSE-2.0
17481  *
17482  * Unless required by applicable law or agreed to in writing, software
17483  * distributed under the License is distributed on an "AS IS" BASIS,
17484  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17485  *
17486  * See the License for the specific language governing permissions and
17487  * limitations under the License.
17488  */
17489 
17490 // !depends ctype.js ctype.isalpha.js ctype.isdigit.js
17491 
17492 /**
17493  * Return whether or not the first character is alphabetic or numeric.<p>
17494  * 
17495  * Depends directive: !depends ctype.isalnum.js
17496  * 
17497  * @param {string|ilib.String|number} ch character or code point to examine
17498  * @return {boolean} true if the first character is alphabetic or numeric
17499  */
17500 ilib.CType.isAlnum = function isAlnum(ch) {
17501 	var num;
17502 	switch (typeof(ch)) {
17503 		case 'number':
17504 			num = ch;
17505 			break;
17506 		case 'string':
17507 			num = ilib.String.toCodePoint(ch, 0);
17508 			break;
17509 		case 'undefined':
17510 			return false;
17511 		default:
17512 			num = ch._toCodePoint(0);
17513 			break;
17514 	}
17515 	return ilib.CType.isAlpha(num) || ilib.CType.isDigit(num);
17516 };
17517 
17518 /**
17519  * @protected
17520  * @param {boolean} sync
17521  * @param {Object} loadParams
17522  * @param {function(*)|undefined} onLoad
17523  */
17524 ilib.CType.isAlnum._init = function (sync, loadParams, onLoad) {
17525 	ilib.CType.isAlpha._init(sync, loadParams, function () {
17526 		ilib.CType.isDigit._init(sync, loadParams, onLoad);
17527 	});
17528 };
17529 
17530 /*
17531  * ctype.isascii.js - Character type is ASCII
17532  * 
17533  * Copyright © 2012-2013, JEDLSoft
17534  *
17535  * Licensed under the Apache License, Version 2.0 (the "License");
17536  * you may not use this file except in compliance with the License.
17537  * You may obtain a copy of the License at
17538  *
17539  *     http://www.apache.org/licenses/LICENSE-2.0
17540  *
17541  * Unless required by applicable law or agreed to in writing, software
17542  * distributed under the License is distributed on an "AS IS" BASIS,
17543  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17544  *
17545  * See the License for the specific language governing permissions and
17546  * limitations under the License.
17547  */
17548 
17549 // !depends ctype.js
17550 
17551 // !data ctype
17552 
17553 /**
17554  * Return whether or not the first character is in the ASCII range.<p>
17555  * 
17556  * Depends directive: !depends ctype.isascii.js
17557  * 
17558  * @param {string|ilib.String|number} ch character or code point to examine
17559  * @return {boolean} true if the first character is in the ASCII range.
17560  */
17561 ilib.CType.isAscii = function (ch) {
17562 	var num;
17563 	switch (typeof(ch)) {
17564 		case 'number':
17565 			num = ch;
17566 			break;
17567 		case 'string':
17568 			num = ilib.String.toCodePoint(ch, 0);
17569 			break;
17570 		case 'undefined':
17571 			return false;
17572 		default:
17573 			num = ch._toCodePoint(0);
17574 			break;
17575 	}
17576 	return ilib.CType._inRange(num, 'ascii', ilib.data.ctype);
17577 };
17578 
17579 /**
17580  * @protected
17581  * @param {boolean} sync
17582  * @param {Object} loadParams
17583  * @param {function(*)|undefined} onLoad
17584  */
17585 ilib.CType.isAscii._init = function (sync, loadParams, onLoad) {
17586 	ilib.CType._init(sync, loadParams, onLoad);
17587 };
17588 
17589 /*
17590  * ctype.isblank.js - Character type is blank
17591  * 
17592  * Copyright © 2012-2013, JEDLSoft
17593  *
17594  * Licensed under the Apache License, Version 2.0 (the "License");
17595  * you may not use this file except in compliance with the License.
17596  * You may obtain a copy of the License at
17597  *
17598  *     http://www.apache.org/licenses/LICENSE-2.0
17599  *
17600  * Unless required by applicable law or agreed to in writing, software
17601  * distributed under the License is distributed on an "AS IS" BASIS,
17602  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17603  *
17604  * See the License for the specific language governing permissions and
17605  * limitations under the License.
17606  */
17607 
17608 // !depends ctype.js
17609 
17610 // !data ctype
17611 
17612 /**
17613  * Return whether or not the first character is a blank character.<p>
17614  * 
17615  * Depends directive: !depends ctype.isblank.js
17616  * 
17617  * ie. a space or a tab.
17618  * @param {string|ilib.String|number} ch character or code point to examine
17619  * @return {boolean} true if the first character is a blank character.
17620  */
17621 ilib.CType.isBlank = function (ch) {
17622 	var num;
17623 	switch (typeof(ch)) {
17624 		case 'number':
17625 			num = ch;
17626 			break;
17627 		case 'string':
17628 			num = ilib.String.toCodePoint(ch, 0);
17629 			break;
17630 		case 'undefined':
17631 			return false;
17632 		default:
17633 			num = ch._toCodePoint(0);
17634 			break;
17635 	}
17636 	return ilib.CType._inRange(num, 'blank', ilib.data.ctype);
17637 };
17638 
17639 /**
17640  * @protected
17641  * @param {boolean} sync
17642  * @param {Object} loadParams
17643  * @param {function(*)|undefined} onLoad
17644  */
17645 ilib.CType.isBlank._init = function (sync, loadParams, onLoad) {
17646 	ilib.CType._init(sync, loadParams, onLoad);
17647 };
17648 
17649 /*
17650  * ctype.iscntrl.js - Character type is control character
17651  * 
17652  * Copyright © 2012-2013, JEDLSoft
17653  *
17654  * Licensed under the Apache License, Version 2.0 (the "License");
17655  * you may not use this file except in compliance with the License.
17656  * You may obtain a copy of the License at
17657  *
17658  *     http://www.apache.org/licenses/LICENSE-2.0
17659  *
17660  * Unless required by applicable law or agreed to in writing, software
17661  * distributed under the License is distributed on an "AS IS" BASIS,
17662  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17663  *
17664  * See the License for the specific language governing permissions and
17665  * limitations under the License.
17666  */
17667 
17668 // !depends ctype.js
17669 
17670 // !data ctype_c
17671 
17672 /**
17673  * Return whether or not the first character is a control character.<p>
17674  * 
17675  * Depends directive: !depends ctype.iscntrl.js
17676  * 
17677  * @param {string|ilib.String|number} ch character or code point to examine
17678  * @return {boolean} true if the first character is a control character.
17679  */
17680 ilib.CType.isCntrl = function (ch) {
17681 	var num;
17682 	switch (typeof(ch)) {
17683 		case 'number':
17684 			num = ch;
17685 			break;
17686 		case 'string':
17687 			num = ilib.String.toCodePoint(ch, 0);
17688 			break;
17689 		case 'undefined':
17690 			return false;
17691 		default:
17692 			num = ch._toCodePoint(0);
17693 			break;
17694 	}
17695 	return ilib.CType._inRange(num, 'Cc', ilib.data.ctype_c);
17696 };
17697 
17698 /**
17699  * @protected
17700  * @param {boolean} sync
17701  * @param {Object} loadParams
17702  * @param {function(*)|undefined} onLoad
17703  */
17704 ilib.CType.isCntrl._init = function (sync, loadParams, onLoad) {
17705 	ilib.CType._load("ctype_c", sync, loadParams, onLoad);
17706 };
17707 
17708 /*
17709  * ctype.isgraph.js - Character type is graph char
17710  * 
17711  * Copyright © 2012-2013, JEDLSoft
17712  *
17713  * Licensed under the Apache License, Version 2.0 (the "License");
17714  * you may not use this file except in compliance with the License.
17715  * You may obtain a copy of the License at
17716  *
17717  *     http://www.apache.org/licenses/LICENSE-2.0
17718  *
17719  * Unless required by applicable law or agreed to in writing, software
17720  * distributed under the License is distributed on an "AS IS" BASIS,
17721  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17722  *
17723  * See the License for the specific language governing permissions and
17724  * limitations under the License.
17725  */
17726 
17727 // !depends ctype.js ctype.isspace.js ctype.iscntrl.js
17728 
17729 /**
17730  * Return whether or not the first character is any printable character
17731  * other than space.<p>
17732  * 
17733  * Depends directive: !depends ctype.isgraph.js
17734  * 
17735  * @param {string|ilib.String|number} ch character or code point to examine
17736  * @return {boolean} true if the first character is any printable character
17737  * other than space. 
17738  */
17739 ilib.CType.isGraph = function (ch) {
17740 	var num;
17741 	switch (typeof(ch)) {
17742 		case 'number':
17743 			num = ch;
17744 			break;
17745 		case 'string':
17746 			num = ilib.String.toCodePoint(ch, 0);
17747 			break;
17748 		case 'undefined':
17749 			return false;
17750 		default:
17751 			num = ch._toCodePoint(0);
17752 			break;
17753 	}
17754 	return typeof(ch) !== 'undefined' && ch.length > 0 && !ilib.CType.isSpace(num) && !ilib.CType.isCntrl(num);
17755 };
17756 
17757 /**
17758  * @protected
17759  * @param {boolean} sync
17760  * @param {Object} loadParams
17761  * @param {function(*)|undefined} onLoad
17762  */
17763 ilib.CType.isGraph._init = function (sync, loadParams, onLoad) {
17764 	ilib.CType.isSpace._init(sync, loadParams, function () {
17765 		ilib.CType.isCntrl._init(sync, loadParams, onLoad);
17766 	});
17767 };
17768 
17769 /*
17770  * ctype.js - Character type definitions
17771  * 
17772  * Copyright © 2012-2013, JEDLSoft
17773  *
17774  * Licensed under the Apache License, Version 2.0 (the "License");
17775  * you may not use this file except in compliance with the License.
17776  * You may obtain a copy of the License at
17777  *
17778  *     http://www.apache.org/licenses/LICENSE-2.0
17779  *
17780  * Unless required by applicable law or agreed to in writing, software
17781  * distributed under the License is distributed on an "AS IS" BASIS,
17782  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17783  *
17784  * See the License for the specific language governing permissions and
17785  * limitations under the License.
17786  */
17787 
17788 // !depends ctype.js
17789 
17790 // !data ctype
17791 
17792 /**
17793  * Return whether or not the first character is an ideographic character.<p>
17794  * 
17795  * Depends directive: !depends ctype.isideo.js
17796  * 
17797  * @param {string|ilib.String|number} ch character or code point to examine
17798  * @return {boolean} true if the first character is an ideographic character.
17799  */
17800 ilib.CType.isIdeo = function (ch) {
17801 	var num;
17802 	switch (typeof(ch)) {
17803 		case 'number':
17804 			num = ch;
17805 			break;
17806 		case 'string':
17807 			num = ilib.String.toCodePoint(ch, 0);
17808 			break;
17809 		case 'undefined':
17810 			return false;
17811 		default:
17812 			num = ch._toCodePoint(0);
17813 			break;
17814 	}
17815 
17816 	return ilib.CType._inRange(num, 'cjk', ilib.data.ctype) ||
17817 		ilib.CType._inRange(num, 'cjkradicals', ilib.data.ctype) ||
17818 		ilib.CType._inRange(num, 'enclosedcjk', ilib.data.ctype) ||
17819 		ilib.CType._inRange(num, 'cjkpunct', ilib.data.ctype) ||
17820 		ilib.CType._inRange(num, 'cjkcompatibility', ilib.data.ctype);
17821 };
17822 
17823 /**
17824  * @protected
17825  * @param {boolean} sync
17826  * @param {Object} loadParams
17827  * @param {function(*)|undefined} onLoad
17828  */
17829 ilib.CType.isIdeo._init = function (sync, loadParams, onLoad) {
17830 	ilib.CType._init(sync, loadParams, onLoad);
17831 };
17832 
17833 /*
17834  * ctype.islower.js - Character type is lower case letter
17835  * 
17836  * Copyright © 2012-2013, JEDLSoft
17837  *
17838  * Licensed under the Apache License, Version 2.0 (the "License");
17839  * you may not use this file except in compliance with the License.
17840  * You may obtain a copy of the License at
17841  *
17842  *     http://www.apache.org/licenses/LICENSE-2.0
17843  *
17844  * Unless required by applicable law or agreed to in writing, software
17845  * distributed under the License is distributed on an "AS IS" BASIS,
17846  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17847  *
17848  * See the License for the specific language governing permissions and
17849  * limitations under the License.
17850  */
17851 
17852 // !depends ctype.js
17853 
17854 // !data ctype_l
17855 
17856 /**
17857  * Return whether or not the first character is lower-case. For alphabetic
17858  * characters in scripts that do not make a distinction between upper- and 
17859  * lower-case, this function always returns true.<p>
17860  * 
17861  * Depends directive: !depends ctype.islower.js
17862  * 
17863  * @param {string|ilib.String|number} ch character or code point to examine
17864  * @return {boolean} true if the first character is lower-case.
17865  */
17866 ilib.CType.isLower = function (ch) {
17867 	var num;
17868 	switch (typeof(ch)) {
17869 		case 'number':
17870 			num = ch;
17871 			break;
17872 		case 'string':
17873 			num = ilib.String.toCodePoint(ch, 0);
17874 			break;
17875 		case 'undefined':
17876 			return false;
17877 		default:
17878 			num = ch._toCodePoint(0);
17879 			break;
17880 	}
17881 
17882 	return ilib.CType._inRange(num, 'Ll', ilib.data.ctype_l);
17883 };
17884 
17885 /**
17886  * @protected
17887  * @param {boolean} sync
17888  * @param {Object} loadParams
17889  * @param {function(*)|undefined} onLoad
17890  */
17891 ilib.CType.isLower._init = function (sync, loadParams, onLoad) {
17892 	ilib.CType._load("ctype_l", sync, loadParams, onLoad);
17893 };
17894 
17895 /*
17896  * ctype.isprint.js - Character type is printable char
17897  * 
17898  * Copyright © 2012-2013, JEDLSoft
17899  *
17900  * Licensed under the Apache License, Version 2.0 (the "License");
17901  * you may not use this file except in compliance with the License.
17902  * You may obtain a copy of the License at
17903  *
17904  *     http://www.apache.org/licenses/LICENSE-2.0
17905  *
17906  * Unless required by applicable law or agreed to in writing, software
17907  * distributed under the License is distributed on an "AS IS" BASIS,
17908  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17909  *
17910  * See the License for the specific language governing permissions and
17911  * limitations under the License.
17912  */
17913 
17914 // !depends ctype.js ctype.iscntrl.js
17915 
17916 /**
17917  * Return whether or not the first character is any printable character,
17918  * including space.<p>
17919  * 
17920  * Depends directive: !depends ctype.isprint.js
17921  * 
17922  * @param {string|ilib.String|number} ch character or code point to examine
17923  * @return {boolean} true if the first character is printable.
17924  */
17925 ilib.CType.isPrint = function (ch) {
17926 	return typeof(ch) !== 'undefined' && ch.length > 0 && !ilib.CType.isCntrl(ch);
17927 };
17928 
17929 /**
17930  * @protected
17931  * @param {boolean} sync
17932  * @param {Object} loadParams
17933  * @param {function(*)|undefined} onLoad
17934  */
17935 ilib.CType.isPrint._init = function (sync, loadParams, onLoad) {
17936 	ilib.CType.isCntrl._init(sync, loadParams, onLoad);
17937 };
17938 
17939 /*
17940  * ctype.ispunct.js - Character type is punctuation
17941  * 
17942  * Copyright © 2012-2013, JEDLSoft
17943  *
17944  * Licensed under the Apache License, Version 2.0 (the "License");
17945  * you may not use this file except in compliance with the License.
17946  * You may obtain a copy of the License at
17947  *
17948  *     http://www.apache.org/licenses/LICENSE-2.0
17949  *
17950  * Unless required by applicable law or agreed to in writing, software
17951  * distributed under the License is distributed on an "AS IS" BASIS,
17952  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17953  *
17954  * See the License for the specific language governing permissions and
17955  * limitations under the License.
17956  */
17957 
17958 // !depends ctype.js
17959 
17960 // !data ctype_p
17961 
17962 /**
17963  * Return whether or not the first character is punctuation.<p>
17964  * 
17965  * Depends directive: !depends ctype.isprint.js
17966  * 
17967  * @param {string|ilib.String|number} ch character or code point to examine
17968  * @return {boolean} true if the first character is punctuation.
17969  */
17970 ilib.CType.isPunct = function (ch) {
17971 	var num;
17972 	switch (typeof(ch)) {
17973 		case 'number':
17974 			num = ch;
17975 			break;
17976 		case 'string':
17977 			num = ilib.String.toCodePoint(ch, 0);
17978 			break;
17979 		case 'undefined':
17980 			return false;
17981 		default:
17982 			num = ch._toCodePoint(0);
17983 			break;
17984 	}
17985 
17986 	return ilib.CType._inRange(num, 'Pd', ilib.data.ctype_p) ||
17987 		ilib.CType._inRange(num, 'Ps', ilib.data.ctype_p) ||
17988 		ilib.CType._inRange(num, 'Pe', ilib.data.ctype_p) ||
17989 		ilib.CType._inRange(num, 'Pc', ilib.data.ctype_p) ||
17990 		ilib.CType._inRange(num, 'Po', ilib.data.ctype_p) ||
17991 		ilib.CType._inRange(num, 'Pi', ilib.data.ctype_p) ||
17992 		ilib.CType._inRange(num, 'Pf', ilib.data.ctype_p);
17993 };
17994 
17995 /**
17996  * @protected
17997  * @param {boolean} sync
17998  * @param {Object} loadParams
17999  * @param {function(*)|undefined} onLoad
18000  */
18001 ilib.CType.isPunct._init = function (sync, loadParams, onLoad) {
18002 	ilib.CType._load("ctype_p", sync, loadParams, onLoad);
18003 };
18004 
18005 /*
18006  * ctype.isupper.js - Character type is upper-case letter
18007  * 
18008  * Copyright © 2012-2013, JEDLSoft
18009  *
18010  * Licensed under the Apache License, Version 2.0 (the "License");
18011  * you may not use this file except in compliance with the License.
18012  * You may obtain a copy of the License at
18013  *
18014  *     http://www.apache.org/licenses/LICENSE-2.0
18015  *
18016  * Unless required by applicable law or agreed to in writing, software
18017  * distributed under the License is distributed on an "AS IS" BASIS,
18018  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18019  *
18020  * See the License for the specific language governing permissions and
18021  * limitations under the License.
18022  */
18023 
18024 // !depends ctype.js
18025 
18026 // !data ctype_l
18027 
18028 /**
18029  * Return whether or not the first character is upper-case. For alphabetic
18030  * characters in scripts that do not make a distinction between upper- and 
18031  * lower-case, this function always returns true.<p>
18032  * 
18033  * Depends directive: !depends ctype.isupper.js
18034  * 
18035  * @param {string|ilib.String|number} ch character or code point to examine
18036  * @return {boolean} true if the first character is upper-case.
18037  */
18038 ilib.CType.isUpper = function (ch) {
18039 	var num;
18040 	switch (typeof(ch)) {
18041 		case 'number':
18042 			num = ch;
18043 			break;
18044 		case 'string':
18045 			num = ilib.String.toCodePoint(ch, 0);
18046 			break;
18047 		case 'undefined':
18048 			return false;
18049 		default:
18050 			num = ch._toCodePoint(0);
18051 			break;
18052 	}
18053 
18054 	return ilib.CType._inRange(num, 'Lu', ilib.data.ctype_l);
18055 };
18056 
18057 /**
18058  * @protected
18059  * @param {boolean} sync
18060  * @param {Object} loadParams
18061  * @param {function(*)|undefined} onLoad
18062  */
18063 ilib.CType.isUpper._init = function (sync, loadParams, onLoad) {
18064 	ilib.CType._load("ctype_l", sync, loadParams, onLoad);
18065 };
18066 
18067 /*
18068  * ctype.isdigit.js - Character type is digit
18069  * 
18070  * Copyright © 2012-2013, JEDLSoft
18071  *
18072  * Licensed under the Apache License, Version 2.0 (the "License");
18073  * you may not use this file except in compliance with the License.
18074  * You may obtain a copy of the License at
18075  *
18076  *     http://www.apache.org/licenses/LICENSE-2.0
18077  *
18078  * Unless required by applicable law or agreed to in writing, software
18079  * distributed under the License is distributed on an "AS IS" BASIS,
18080  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18081  *
18082  * See the License for the specific language governing permissions and
18083  * limitations under the License.
18084  */
18085 
18086 // !depends ctype.js
18087 
18088 // !data ctype
18089 
18090 /**
18091  * Return whether or not the first character is a hexadecimal digit written
18092  * in the Latin script. (0-9 or A-F)<p>
18093  * 
18094  * Depends directive: !depends ctype.isxdigit.js
18095  * 
18096  * @param {string|ilib.String|number} ch character or code point to examine
18097  * @return {boolean} true if the first character is a hexadecimal digit written
18098  * in the Latin script.
18099  */
18100 ilib.CType.isXdigit = function (ch) {
18101 	var num;
18102 	switch (typeof(ch)) {
18103 		case 'number':
18104 			num = ch;
18105 			break;
18106 		case 'string':
18107 			num = ilib.String.toCodePoint(ch, 0);
18108 			break;
18109 		case 'undefined':
18110 			return false;
18111 		default:
18112 			num = ch._toCodePoint(0);
18113 			break;
18114 	}
18115 
18116 	return ilib.CType._inRange(num, 'xdigit', ilib.data.ctype);
18117 };
18118 
18119 /**
18120  * @protected
18121  * @param {boolean} sync
18122  * @param {Object} loadParams
18123  * @param {function(*)|undefined} onLoad
18124  */
18125 ilib.CType.isXdigit._init = function (sync, loadParams, onLoad) {
18126 	ilib.CType._init(sync, loadParams, onLoad);
18127 };
18128 
18129 /*
18130  * ctype.isscript.js - Character type is script
18131  * 
18132  * Copyright © 2012-2013, JEDLSoft
18133  *
18134  * Licensed under the Apache License, Version 2.0 (the "License");
18135  * you may not use this file except in compliance with the License.
18136  * You may obtain a copy of the License at
18137  *
18138  *     http://www.apache.org/licenses/LICENSE-2.0
18139  *
18140  * Unless required by applicable law or agreed to in writing, software
18141  * distributed under the License is distributed on an "AS IS" BASIS,
18142  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18143  *
18144  * See the License for the specific language governing permissions and
18145  * limitations under the License.
18146  */
18147 
18148 // !depends ctype.js
18149 
18150 // !data scriptToRange
18151 
18152 /**
18153  * Return whether or not the first character in the given string is 
18154  * in the given script. The script is given as the 4-letter ISO
18155  * 15924 script code.<p>
18156  * 
18157  * Depends directive: !depends ctype.isscript.js
18158  * 
18159  * @param {string|ilib.String|number} ch character or code point to examine
18160  * @param {string} script the 4-letter ISO 15924 to query against
18161  * @return {boolean} true if the first character is in the given script, and
18162  * false otherwise
18163  */
18164 ilib.CType.isScript = function (ch, script) {
18165 	var num;
18166 	switch (typeof(ch)) {
18167 		case 'number':
18168 			num = ch;
18169 			break;
18170 		case 'string':
18171 			num = ilib.String.toCodePoint(ch, 0);
18172 			break;
18173 		case 'undefined':
18174 			return false;
18175 		default:
18176 			num = ch._toCodePoint(0);
18177 			break;
18178 	}
18179 
18180 	return ilib.CType._inRange(num, script, ilib.data.scriptToRange);
18181 };
18182 
18183 /**
18184  * @protected
18185  * @param {boolean} sync
18186  * @param {Object} loadParams
18187  * @param {function(*)|undefined} onLoad
18188  */
18189 ilib.CType.isScript._init = function (sync, loadParams, onLoad) {
18190 	ilib.CType._load("scriptToRange", sync, loadParams, onLoad);
18191 };
18192 
18193 
18194 /*
18195  * scriptinfo.js - information about scripts
18196  * 
18197  * Copyright © 2012-2014, JEDLSoft
18198  *
18199  * Licensed under the Apache License, Version 2.0 (the "License");
18200  * you may not use this file except in compliance with the License.
18201  * You may obtain a copy of the License at
18202  *
18203  *     http://www.apache.org/licenses/LICENSE-2.0
18204  *
18205  * Unless required by applicable law or agreed to in writing, software
18206  * distributed under the License is distributed on an "AS IS" BASIS,
18207  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18208  *
18209  * See the License for the specific language governing permissions and
18210  * limitations under the License.
18211  */
18212 
18213 // !depends ilibglobal.js
18214 
18215 // !data scripts
18216 
18217 /**
18218  * @class
18219  * Create a new script info instance. This class encodes information about
18220  * scripts, which are sets of characters used in a writing system.<p>
18221  * 
18222  * The options object may contain any of the following properties:
18223  * 
18224  * <ul>
18225  * <li><i>onLoad</i> - a callback function to call when the script info object is fully 
18226  * loaded. When the onLoad option is given, the script info object will attempt to
18227  * load any missing locale data using the ilib loader callback.
18228  * When the constructor is done (even if the data is already preassembled), the 
18229  * onLoad function is called with the current instance as a parameter, so this
18230  * callback can be used with preassembled or dynamic loading or a mix of the two.
18231  * 
18232  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
18233  * asynchronously. If this option is given as "false", then the "onLoad"
18234  * callback must be given, as the instance returned from this constructor will
18235  * not be usable for a while. 
18236  *
18237  * <li><i>loadParams</i> - an object containing parameters to pass to the 
18238  * loader callback function when locale data is missing. The parameters are not
18239  * interpretted or modified in any way. They are simply passed along. The object 
18240  * may contain any property/value pairs as long as the calling code is in
18241  * agreement with the loader callback function as to what those parameters mean.
18242  * </ul>
18243  * 
18244  * Depends directive: !depends scriptinfo.js
18245  * 
18246  * @constructor
18247  * @param {string} script The ISO 15924 4-letter identifier for the script
18248  * @param {Object} options parameters to initialize this matcher 
18249  */
18250 ilib.ScriptInfo = function(script, options) {
18251 	var sync = true,
18252 	    loadParams = undefined;
18253 	
18254 	this.script = script;
18255 	
18256 	if (options) {
18257 		if (typeof(options.sync) !== 'undefined') {
18258 			sync = (options.sync == true);
18259 		}
18260 		
18261 		if (typeof(options.loadParams) !== 'undefined') {
18262 			loadParams = options.loadParams;
18263 		}
18264 	}
18265 
18266 	if (!ilib.ScriptInfo.cache) {
18267 		ilib.ScriptInfo.cache = {};
18268 	}
18269 
18270 	if (!ilib.data.scripts) {
18271 		ilib.loadData({
18272 			object: ilib.ScriptInfo, 
18273 			locale: "-", 
18274 			name: "scripts.json", 
18275 			sync: sync, 
18276 			loadParams: loadParams, 
18277 			callback: ilib.bind(this, function (info) {
18278 				if (!info) {
18279 					info = {"Latn":{"nb":215,"nm":"Latin","lid":"Latin","rtl":false,"ime":false,"casing":true}};
18280 					var spec = this.locale.getSpec().replace(/-/g, "_");
18281 					ilib.ScriptInfo.cache[spec] = info;
18282 				}
18283 				ilib.data.scripts = info;
18284 				this.info = script && ilib.data.scripts[script];
18285 				if (options && typeof(options.onLoad) === 'function') {
18286 					options.onLoad(this);
18287 				}
18288 			})
18289 		});
18290 	} else {
18291 		this.info = ilib.data.scripts[script];
18292 	}
18293 
18294 };
18295 
18296 /**
18297  * Return an array of all ISO 15924 4-letter identifier script identifiers that
18298  * this copy of ilib knows about.
18299  * @static
18300  * @return {Array.<string>} an array of all script identifiers that this copy of
18301  * ilib knows about
18302  */
18303 ilib.ScriptInfo.getAllScripts = function() {
18304 	var ret = [],
18305 		script = undefined,
18306 		scripts = ilib.data.scripts;
18307 	
18308 	for (script in scripts) {
18309 		if (script && scripts[script]) {
18310 			ret.push(script);
18311 		}
18312 	}
18313 	
18314 	return ret;
18315 };
18316 
18317 ilib.ScriptInfo.prototype = {
18318 	/**
18319 	 * Return the 4-letter ISO 15924 identifier associated
18320 	 * with this script.
18321 	 * @return {string} the 4-letter ISO code for this script
18322 	 */
18323 	getCode: function () {
18324 		return this.info && this.script;
18325 	},
18326 	
18327 	/**
18328 	 * Get the ISO 15924 code number associated with this
18329 	 * script.
18330 	 * 
18331 	 * @return {number} the ISO 15924 code number
18332 	 */
18333 	getCodeNumber: function () {
18334 		return this.info && this.info.nb || 0;
18335 	},
18336 	
18337 	/**
18338 	 * Get the name of this script in English.
18339 	 * 
18340 	 * @return {string} the name of this script in English
18341 	 */
18342 	getName: function () {
18343 		return this.info && this.info.nm;
18344 	},
18345 	
18346 	/**
18347 	 * Get the long identifier assciated with this script.
18348 	 * 
18349 	 * @return {string} the long identifier of this script
18350 	 */
18351 	getLongCode: function () {
18352 		return this.info && this.info.lid;
18353 	},
18354 	
18355 	/**
18356 	 * Return the usual direction that text in this script is written
18357 	 * in. Possible return values are "rtl" for right-to-left,
18358 	 * "ltr" for left-to-right, and "ttb" for top-to-bottom.
18359 	 * 
18360 	 * @return {string} the usual direction that text in this script is
18361 	 * written in
18362 	 */
18363 	getScriptDirection: function() {
18364 		return (this.info && typeof(this.info.rtl) !== 'undefined' && this.info.rtl) ? "rtl" : "ltr";
18365 	},
18366 	
18367 	/**
18368 	 * Return true if this script typically requires an input method engine
18369 	 * to enter its characters.
18370 	 * 
18371 	 * @return {boolean} true if this script typically requires an IME
18372 	 */
18373 	getNeedsIME: function () {
18374 		return this.info && this.info.ime ? true : false; // converts undefined to false
18375 	},
18376 	
18377 	/**
18378 	 * Return true if this script uses lower- and upper-case characters.
18379 	 * 
18380 	 * @return {boolean} true if this script uses letter case
18381 	 */
18382 	getCasing: function () {
18383 		return this.info && this.info.casing ? true : false; // converts undefined to false
18384 	}
18385 };
18386 /*
18387  * nameprs.js - Person name parser
18388  *
18389  * Copyright © 2013-2014, JEDLSoft
18390  *
18391  * Licensed under the Apache License, Version 2.0 (the "License");
18392  * you may not use this file except in compliance with the License.
18393  * You may obtain a copy of the License at
18394  *
18395  *     http://www.apache.org/licenses/LICENSE-2.0
18396  *
18397  * Unless required by applicable law or agreed to in writing, software
18398  * distributed under the License is distributed on an "AS IS" BASIS,
18399  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18400  *
18401  * See the License for the specific language governing permissions and
18402  * limitations under the License.
18403  */
18404 
18405 /* !depends 
18406 ilibglobal.js 
18407 locale.js
18408 util/utils.js 
18409 ctype.isalpha.js 
18410 ctype.isideo.js 
18411 ctype.ispunct.js 
18412 ctype.isspace.js
18413 util/jsutils.js 
18414 */
18415 
18416 // !data name
18417 
18418 // notes:
18419 // icelandic given names: http://en.wiktionary.org/wiki/Appendix:Icelandic_given_names
18420 // danish approved given names: http://www.familiestyrelsen.dk/samliv/navne/
18421 // http://www.mentalfloss.com/blogs/archives/59277
18422 // other countries with first name restrictions: Norway, China, New Zealand, Japan, Sweden, Germany, Hungary
18423 
18424 /**
18425  * @class
18426  * A class to parse names of people. Different locales have different conventions when it
18427  * comes to naming people.<p>
18428  *
18429  * The options can contain any of the following properties:
18430  *
18431  * <ul>
18432  * <li><i>locale</i> - use the rules and conventions of the given locale in order to parse
18433  * the name
18434  * <li><i>style</i> - explicitly use the named style to parse the name. Valid values so
18435  * far are "western" and "asian". If this property is not specified, then the style will
18436  * be gleaned from the name itself. This class will count the total number of Latin or Asian
18437  * characters. If the majority of the characters are in one style, that style will be
18438  * used to parse the whole name.
18439  * <li><i>order</i> - explicitly use the given order for names. In some locales, such
18440  * as Russian, names may be written equally validly as "givenName familyName" or "familyName
18441  * givenName". This option tells the parser which order to prefer, and overrides the
18442  * default order for the locale. Valid values are "gf" (given-family) or "fg" (family-given).
18443  * <li><i>useSpaces</i> - explicitly specifies whether to use spaces or not between the given name , middle name
18444  * and family name.
18445  * <li>onLoad - a callback function to call when the name info is fully
18446  * loaded and the name has been parsed. When the onLoad option is given, the name object
18447  * will attempt to load any missing locale data using the ilib loader callback.
18448  * When the constructor is done (even if the data is already preassembled), the
18449  * onLoad function is called with the current instance as a parameter, so this
18450  * callback can be used with preassembled or dynamic loading or a mix of the two.
18451  *
18452  * <li>sync - tell whether to load any missing locale data synchronously or
18453  * asynchronously. If this option is given as "false", then the "onLoad"
18454  * callback must be given, as the instance returned from this constructor will
18455  * not be usable for a while.
18456  *
18457  * <li><i>loadParams</i> - an object containing parameters to pass to the
18458  * loader callback function when locale data is missing. The parameters are not
18459  * interpretted or modified in any way. They are simply passed along. The object
18460  * may contain any property/value pairs as long as the calling code is in
18461  * agreement with the loader callback function as to what those parameters mean.
18462  * </ul>
18463  *
18464  * When the parser has completed its parsing, it fills in the fields listed below.<p>
18465  *
18466  * For names that include auxilliary words, such as the family name "van der Heijden", all
18467  * of the auxilliary words ("van der") will be included in the field.<p>
18468  *
18469  * For names in Spanish locales, it is assumed that the family name is doubled. That is,
18470  * a person may have a paternal family name followed by a maternal family name. All
18471  * family names will be listed in the familyName field as normal, separated by spaces.
18472  * When formatting the short version of such names, only the paternal family name will
18473  * be used.
18474  *
18475  * Depends directive: !depends nameprs.js
18476  *
18477  * @constructor
18478  * @param {string|ilib.Name=} name the name to parse
18479  * @param {Object=} options Options governing the construction of this name instance
18480  */
18481 ilib.Name = function (name, options) {
18482     var sync = true;
18483 
18484     if (!name || name.length === 0) {
18485     	return;
18486     }
18487 
18488     this.loadParams = {};
18489 
18490     if (options) {
18491         if (options.locale) {
18492             this.locale = (typeof (options.locale) === 'string') ? new ilib.Locale(options.locale) : options.locale;
18493         }
18494 
18495         if (options.style && (options.style === "asian" || options.style === "western")) {
18496             this.style = options.style;
18497         }
18498 
18499         if (options.order && (options.order === "gmf" || options.order === "fmg" || options.order === "fgm")) {
18500             this.order = options.order;
18501         }
18502 
18503         if (typeof (options.sync) !== 'undefined') {
18504             sync = (options.sync == true);
18505         }
18506 
18507         if (typeof (options.loadParams) !== 'undefined') {
18508             this.loadParams = options.loadParams;
18509         }
18510     }
18511 
18512     if (!ilib.Name.cache) {
18513         ilib.Name.cache = {};
18514     }
18515 
18516 	this.locale = this.locale || new ilib.Locale();
18517 	
18518 	ilib.CType.isAlpha._init(sync, this.loadParams, /** @type {function()|undefined} */ ilib.bind(this, function() {
18519 		ilib.CType.isIdeo._init(sync, this.loadParams, /** @type {function()|undefined} */ ilib.bind(this, function() {
18520 			ilib.CType.isPunct._init(sync, this.loadParams, /** @type {function()|undefined} */ ilib.bind(this, function() {
18521 				ilib.CType.isSpace._init(sync, this.loadParams, /** @type {function()|undefined} */ ilib.bind(this, function() {
18522 					ilib.loadData({
18523 						object: ilib.Name, 
18524 						locale: this.locale, 
18525 						name: "name.json", 
18526 						sync: sync, 
18527 						loadParams: this.loadParams, 
18528 						callback: ilib.bind(this, function (info) {
18529 							if (!info) {
18530 								info = ilib.Name.defaultInfo;
18531 								var spec = this.locale.getSpec().replace(/-/g, "_");
18532 								ilib.Name.cache[spec] = info;
18533 							}
18534                             if (typeof (name) === 'object') {
18535     							// copy constructor
18536 							    /**
18537 							     * The prefixes for this name
18538 							     * @type {string|Array.<string>}
18539 							     */
18540 							    this.prefix = name.prefix;
18541 							    /**
18542 							     * The given (personal) name in this name.
18543 							     * @type {string|Array.<string>}
18544 							     */
18545 							    this.givenName = name.givenName;
18546 							    /**
18547 							     * The middle names used in this name. If there are multiple middle names, they all
18548 							     * appear in this field separated by spaces.
18549 							     * @type {string|Array.<string>}
18550 							     */
18551 							    this.middleName = name.middleName;
18552 							    /**
18553 							     * The family names in this name. If there are multiple family names, they all
18554 							     * appear in this field separated by spaces.
18555 							     * @type {string|Array.<string>}
18556 							     */
18557 							    this.familyName = name.familyName;
18558 							    /**
18559 							     * The suffixes for this name. If there are multiple suffixes, they all
18560 							     * appear in this field separated by spaces.
18561 							     * @type {string|Array.<string>}
18562 							     */
18563 							    this.suffix = name.suffix;
18564 
18565 							    // private properties
18566 							    this.locale = name.locale;
18567 							    this.style = name.style;
18568 							    this.order = name.order;
18569 							    this.useSpaces = name.useSpaces;
18570 							    this.isAsianName = name.isAsianName;
18571 					    	    return;
18572 						    }
18573 							/** 
18574 							 * @type {{
18575 							 *   nameStyle:string,
18576 							 *   order:string,
18577 							 *   prefixes:Array.<string>,
18578 							 *   suffixes:Array.<string>,
18579 							 *   auxillaries:Array.<string>,
18580 							 *   honorifics:Array.<string>,
18581 							 *   knownFamilyNames:Array.<string>,
18582 							 *   noCompoundFamilyNames:boolean,
18583 							 *   sortByHeadWord:boolean
18584 							 * }} */
18585 							this.info = info;
18586 							this._init(name);
18587 							if (options && typeof(options.onLoad) === 'function') {
18588 								options.onLoad(this);
18589 							}
18590 						})
18591 					});					
18592 				}));
18593 			}));
18594 		}));
18595 	}));
18596 };
18597 
18598 ilib.Name.defaultInfo = ilib.data.name ||  {
18599 	"components": {
18600 		"short": {
18601 			"g": 1,
18602 			"f": 1
18603 		},
18604 		"medium": {
18605 			"g": 1,
18606 			"m": 1,
18607 			"f": 1
18608 		},
18609 		"long": {
18610 			"p": 1,
18611 			"g": 1,
18612 			"m": 1,
18613 			"f": 1
18614 		},
18615 		"full": {
18616 			"p": 1,
18617 			"g": 1,
18618 			"m": 1,
18619 			"f": 1,
18620 			"s": 1
18621 		}
18622 	},
18623 	"format": "{prefix} {givenName} {middleName} {familyName}{suffix}",
18624 	"sortByHeadWord": false,
18625 	"nameStyle": "western",
18626 	"conjunctions": {
18627 		"and1": "and",
18628 		"and2": "and",
18629 		"or1": "or",
18630 		"or2": "or"
18631 	},
18632 	"auxillaries": {
18633 		"von": 1,
18634 		"von der": 1,
18635 		"von den": 1,
18636 		"van": 1,
18637 		"van der": 1,
18638         "van de": 1,
18639         "van den": 1,
18640         "de": 1,
18641         "di": 1,
18642 	    "de": 1,
18643 		"la": 1,
18644 		"lo": 1,
18645         "des": 1,
18646         "le": 1,
18647         "les": 1,
18648 		"du": 1,
18649         "de la": 1,
18650         "del": 1,
18651         "de los": 1,
18652         "de las": 1
18653 	},
18654 	"prefixes": [
18655 		"doctor",
18656 		"dr",
18657 		"mr",
18658 		"mrs",
18659 		"ms",
18660 		"mister",
18661 		"madame",
18662 		"madamoiselle",
18663 		"miss",
18664 		"monsieur",
18665 		"señor",
18666         "señora",
18667         "señorita"
18668 	],
18669 	"suffixes": [
18670 		",",
18671 		"junior",
18672 		"jr",
18673 		"senior",
18674 		"sr",
18675 		"i",
18676 		"ii",
18677 		"iii",
18678 		"esq",
18679 		"phd",
18680 		"md"
18681 	],
18682     "patronymicName":[ ],
18683     "familyNames":[ ]
18684 };
18685 
18686 /**
18687  * Return true if the given character is in the range of the Han, Hangul, or kana
18688  * scripts.
18689  * @static
18690  * @protected
18691  */
18692 ilib.Name._isAsianChar = function(c) {
18693 	return ilib.CType.isIdeo(c) ||
18694 		ilib.CType.withinRange(c, "hangul") ||
18695 		ilib.CType.withinRange(c, "hiragana") ||
18696 		ilib.CType.withinRange(c, "katakana");
18697 };
18698 
18699 
18700 /**
18701  * @static
18702  * @protected
18703  */
18704 ilib.Name._isAsianName = function (name, language) {
18705     // the idea is to count the number of asian chars and the number
18706     // of latin chars. If one is greater than the other, choose
18707     // that style.
18708     var asian = 0,
18709         latin = 0,
18710         i;
18711 
18712     if (name && name.length > 0) {
18713         for (i = 0; i < name.length; i++) {
18714         	var c = name.charAt(i);
18715 
18716             if (ilib.Name._isAsianChar(c)) {
18717                 if (language =="ko" || language =="ja" || language =="zh") {
18718                     return true;
18719                 }
18720                 asian++;
18721             } else if (ilib.CType.isAlpha(c)) {
18722                 if (!language =="ko" || !language =="ja" || !language =="zh") {
18723                     return false;
18724                 }
18725                 latin++;
18726             }
18727         }
18728 
18729         return latin < asian;
18730     }
18731 
18732     return false;
18733 };
18734 
18735 /**
18736  * Return true if any Latin letters are found in the string. Return
18737  * false if all the characters are non-Latin.
18738  * @static
18739  * @protected
18740  */
18741 ilib.Name._isEuroName = function (name, language) {
18742     var c,
18743         n = new ilib.String(name),
18744         it = n.charIterator();
18745 
18746     while (it.hasNext()) {
18747         c = it.next();
18748 
18749         if (!ilib.Name._isAsianChar(c) && !ilib.CType.isPunct(c) && !ilib.CType.isSpace(c)) {
18750             return true;
18751         } else if (ilib.Name._isAsianChar(c) && (language =="ko" || language =="ja" || language =="zh")) {
18752             return false;
18753         }
18754     }
18755     return false;
18756 };
18757 
18758 ilib.Name.prototype = {
18759     /**
18760      * @protected
18761      */
18762     _init: function (name) {
18763         var parts, prefixArray, prefix, prefixLower,
18764             suffixArray, suffix, suffixLower,
18765             i, info, hpSuffix;
18766         var currentLanguage = this.locale.getLanguage();
18767 
18768         if (name) {
18769             // for DFISH-12905, pick off the part that the LDAP server automatically adds to our names in HP emails
18770             i = name.search(/\s*[,\/\(\[\{<]/);
18771             if (i !== -1) {
18772                 hpSuffix = name.substring(i);
18773                 hpSuffix = hpSuffix.replace(/\s+/g, ' '); // compress multiple whitespaces
18774                 suffixArray = hpSuffix.split(" ");
18775                 var conjunctionIndex = this._findLastConjunction(suffixArray);
18776                 if (conjunctionIndex > -1) {
18777                     // it's got conjunctions in it, so this is not really a suffix
18778                     hpSuffix = undefined;
18779                 } else {
18780                     name = name.substring(0, i);
18781                 }
18782             }
18783 
18784             this.isAsianName = ilib.Name._isAsianName(name, currentLanguage);
18785             if (this.info.nameStyle === "asian" || this.info.order === "fmg" || this.info.order === "fgm") {
18786                 info = this.isAsianName ? this.info : ilib.data.name;
18787             } else {
18788                 info = this.isAsianName ? ilib.data.name : this.info;
18789             }
18790 
18791             if (this.isAsianName) {
18792                 // all-asian names
18793                 if (this.useSpaces == false) {
18794                     name = name.replace(/\s+/g, ''); // eliminate all whitespaces
18795                 }
18796                 parts = name.trim().split('');
18797             }
18798             //} 
18799             else {
18800                 name = name.replace(/, /g, ' , ');
18801                 name = name.replace(/\s+/g, ' '); // compress multiple whitespaces
18802                 parts = name.trim().split(' ');
18803             }
18804 
18805             // check for prefixes
18806             if (parts.length > 1) {
18807                 for (i = parts.length; i > 0; i--) {
18808                     prefixArray = parts.slice(0, i);
18809                     prefix = prefixArray.join(this.isAsianName ? '' : ' ');
18810                     prefixLower = prefix.toLowerCase();
18811                     prefixLower = prefixLower.replace(/[,\.]/g, ''); // ignore commas and periods
18812                     if (this.info.prefixes &&
18813                         (this.info.prefixes.indexOf(prefixLower) > -1 || this._isConjunction(prefixLower))) {
18814                         if (this.prefix) {
18815                             if (!this.isAsianName) {
18816                                 this.prefix += ' ';
18817                             }
18818                             this.prefix += prefix;
18819                         } else {
18820                             this.prefix = prefix;
18821                         }
18822                         parts = parts.slice(i);
18823                         i = parts.length;
18824                     }
18825                 }
18826             }
18827             // check for suffixes
18828             if (parts.length > 1) {
18829                 for (i = parts.length; i > 0; i--) {
18830                     suffixArray = parts.slice(-i);
18831                     suffix = suffixArray.join(this.isAsianName ? '' : ' ');
18832                     suffixLower = suffix.toLowerCase();
18833                     suffixLower = suffixLower.replace(/[\.]/g, ''); // ignore periods
18834                     if (this.info.suffixes && this.info.suffixes.indexOf(suffixLower) > -1) {
18835                         if (this.suffix) {
18836                             if (!this.isAsianName && !ilib.CType.isPunct(this.suffix.charAt(0))) {
18837                                 this.suffix = ' ' + this.suffix;
18838                             }
18839                             this.suffix = suffix + this.suffix;
18840                         } else {
18841                             this.suffix = suffix;
18842                         }
18843                         parts = parts.slice(0, parts.length - i);
18844                         i = parts.length;
18845                     }
18846                 }
18847             }
18848 
18849             if (hpSuffix) {
18850                 this.suffix = (this.suffix && this.suffix + hpSuffix) || hpSuffix;
18851             }
18852 
18853             // adjoin auxillary words to their headwords
18854             if (parts.length > 1 && !this.isAsianName) {
18855                 parts = this._joinAuxillaries(parts, this.isAsianName);
18856             }
18857 
18858             if (this.isAsianName) {
18859                 this._parseAsianName(parts, currentLanguage);
18860             } else {
18861                 this._parseWesternName(parts);
18862             }
18863 
18864             this._joinNameArrays();
18865         }
18866     },
18867 
18868     /**
18869 	 * @return {number} 
18870 	 *
18871 	_findSequence: function(parts, hash, isAsian) {
18872 		var sequence, sequenceLower, sequenceArray, aux = [], i, ret = {};
18873 		
18874 		if (parts.length > 0 && hash) {
18875 			//console.info("_findSequence: finding sequences");
18876 			for (var start = 0; start < parts.length-1; start++) {
18877 				for ( i = parts.length; i > start; i-- ) {
18878 					sequenceArray = parts.slice(start, i);
18879 					sequence = sequenceArray.join(isAsian ? '' : ' ');
18880 					sequenceLower = sequence.toLowerCase();
18881 					sequenceLower = sequenceLower.replace(/[,\.]/g, '');  // ignore commas and periods
18882 					
18883 					//console.info("_findSequence: checking sequence: '" + sequenceLower + "'");
18884 					
18885 					if ( sequenceLower in hash ) {
18886 						ret.match = sequenceArray;
18887 						ret.start = start;
18888 						ret.end = i;
18889 						return ret;
18890 						//console.info("_findSequence: Found sequence '" + sequence + "' New parts list is " + JSON.stringify(parts));
18891 					}
18892 				}
18893 			}
18894 		}
18895 	
18896 		return undefined;
18897 	},
18898 	*/
18899 
18900     /**
18901      * @protected
18902      * @param {Array} parts
18903      * @param {Array} names
18904      * @param {boolean} isAsian
18905      * @param {boolean=} noCompoundPrefix
18906      */
18907     _findPrefix: function (parts, names, isAsian, noCompoundPrefix) {
18908         var i, prefix, prefixLower, prefixArray, aux = [];
18909 
18910         if (parts.length > 0 && names) {
18911             for (i = parts.length; i > 0; i--) {
18912                 prefixArray = parts.slice(0, i);
18913                 prefix = prefixArray.join(isAsian ? '' : ' ');
18914                 prefixLower = prefix.toLowerCase();
18915                 prefixLower = prefixLower.replace(/[,\.]/g, ''); // ignore commas and periods
18916 
18917                 if (prefixLower in names) {
18918                     aux = aux.concat(isAsian ? prefix : prefixArray);
18919                     if (noCompoundPrefix) {
18920                     	// don't need to parse further. Just return it as is.
18921                     	return aux;
18922                     }
18923                     parts = parts.slice(i);
18924                     i = parts.length + 1;
18925                 }
18926             }
18927         }
18928 
18929         return aux;
18930     },
18931 
18932     /**
18933      * @protected
18934      */
18935     _findSuffix: function (parts, names, isAsian) {
18936         var i, j, seq = "";
18937 
18938         for (i = 0; i < names.length; i++) {
18939             if (parts.length >= names[i].length) {
18940                 j = 0;
18941                 while (j < names[i].length && parts[parts.length - j] === names[i][names[i].length - j]) {
18942                     j++;
18943                 }
18944                 if (j >= names[i].length) {
18945                     seq = parts.slice(parts.length - j).join(isAsian ? "" : " ") + (isAsian ? "" : " ") + seq;
18946                     parts = parts.slice(0, parts.length - j);
18947                     i = -1; // restart the search
18948                 }
18949             }
18950         }
18951 
18952         this.suffix = seq;
18953         return parts;
18954     },
18955 
18956     /**
18957      * @protected
18958      * Tell whether or not the given word is a conjunction in this language.
18959      * @param {string} word the word to test
18960      * @return {boolean} true if the word is a conjunction
18961      */
18962     _isConjunction: function _isConjunction(word) {
18963         return (this.info.conjunctions.and1 === word ||
18964             this.info.conjunctions.and2 === word ||
18965             this.info.conjunctions.or1 === word ||
18966             this.info.conjunctions.or2 === word ||
18967             ("&" === word) ||
18968             ("+" === word));
18969     },
18970 
18971     /**
18972      * Find the last instance of 'and' in the name
18973      * @protected
18974      * @param {Array.<string>} parts
18975      * @return {number}
18976      */
18977     _findLastConjunction: function _findLastConjunction(parts) {
18978         var conjunctionIndex = -1,
18979             index, part;
18980 
18981         for (index = 0; index < parts.length; index++) {
18982             part = parts[index];
18983             if (typeof (part) === 'string') {
18984                 part = part.toLowerCase();
18985                 // also recognize English
18986                 if ("and" === part || "or" === part || "&" === part || "+" === part) {
18987                     conjunctionIndex = index;
18988                 }
18989                 if (this._isConjunction(part)) {
18990                     conjunctionIndex = index;
18991                 }
18992             }
18993         }
18994         return conjunctionIndex;
18995     },
18996 
18997     /**
18998      * @protected
18999      * @param {Array.<string>} parts the current array of name parts
19000      * @param {boolean} isAsian true if the name is being parsed as an Asian name
19001      * @return {Array.<string>} the remaining parts after the prefixes have been removed
19002      */
19003     _extractPrefixes: function (parts, isAsian) {
19004         var i = this._findPrefix(parts, this.info.prefixes, isAsian);
19005         if (i > 0) {
19006             this.prefix = parts.slice(0, i).join(isAsian ? "" : " ");
19007             return parts.slice(i);
19008         }
19009         // prefixes not found, so just return the array unmodified
19010         return parts;
19011     },
19012 
19013     /**
19014      * @protected
19015      * @param {Array.<string>} parts the current array of name parts
19016      * @param {boolean} isAsian true if the name is being parsed as an Asian name
19017      * @return {Array.<string>} the remaining parts after the suffices have been removed
19018      */
19019     _extractSuffixes: function (parts, isAsian) {
19020         var i = this._findSuffix(parts, this.info.suffixes, isAsian);
19021         if (i > 0) {
19022             this.suffix = parts.slice(i).join(isAsian ? "" : " ");
19023             return parts.slice(0, i);
19024         }
19025         // suffices not found, so just return the array unmodified
19026         return parts;
19027     },
19028 
19029     /**
19030      * Adjoin auxillary words to their head words.
19031      * @protected
19032      * @param {Array.<string>} parts the current array of name parts
19033      * @param {boolean} isAsian true if the name is being parsed as an Asian name
19034      * @return {Array.<string>} the parts after the auxillary words have been plucked onto their head word
19035      */
19036     _joinAuxillaries: function (parts, isAsian) {
19037         var start, i, prefixArray, prefix, prefixLower;
19038 
19039         if (this.info.auxillaries && (parts.length > 2 || this.prefix)) {
19040             for (start = 0; start < parts.length - 1; start++) {
19041                 for (i = parts.length; i > start; i--) {
19042                     prefixArray = parts.slice(start, i);
19043                     prefix = prefixArray.join(' ');
19044                     prefixLower = prefix.toLowerCase();
19045                     prefixLower = prefixLower.replace(/[,\.]/g, ''); // ignore commas and periods
19046 
19047                     if (prefixLower in this.info.auxillaries) {
19048                         parts.splice(start, i + 1 - start, prefixArray.concat(parts[i]));
19049                         i = start;
19050                     }
19051                 }
19052             }
19053         }
19054 
19055         return parts;
19056     },
19057 
19058     /**
19059      * Recursively join an array or string into a long string.
19060      * @protected
19061      */
19062     _joinArrayOrString: function _joinArrayOrString(part) {
19063         var i;
19064         if (typeof (part) === 'object') {
19065             for (i = 0; i < part.length; i++) {
19066                 part[i] = this._joinArrayOrString(part[i]);
19067             }
19068             var ret = "";
19069             part.forEach(function (segment) {
19070                 if (ret.length > 0 && !ilib.CType.isPunct(segment.charAt(0))) {
19071                     ret += ' ';
19072                 }
19073                 ret += segment;
19074             });
19075 
19076             return ret;
19077         }
19078 
19079         return part;
19080     },
19081 
19082     /**
19083      * @protected
19084      */
19085     _joinNameArrays: function _joinNameArrays() {
19086         var prop;
19087         for (prop in this) {
19088 
19089             if (this[prop] !== undefined && typeof (this[prop]) === 'object' && this[prop] instanceof Array) {
19090 
19091                 this[prop] = this._joinArrayOrString(this[prop]);
19092             }
19093         }
19094     },
19095 
19096     /**
19097      * @protected
19098      */
19099     _parseAsianName: function (parts, language) {
19100         var familyNameArray = this._findPrefix(parts, this.info.knownFamilyNames, true, this.info.noCompoundFamilyNames);
19101         var tempFullName = parts.join('');
19102 
19103         if (familyNameArray && familyNameArray.length > 0) {
19104             this.familyName = familyNameArray.join('');
19105             this.givenName = parts.slice(this.familyName.length).join('');
19106             
19107             //Overide parsing rules if spaces are found in korean
19108             if (language === "ko" && tempFullName.search(/\s*[/\s]/) > -1 && !this.suffix) {
19109                 this._parseKoreanName(tempFullName);
19110             }
19111         } else if (this.locale.getLanguage() === "ja") {
19112             this._parseJapaneseName(parts);
19113         } else if (this.suffix || this.prefix) {
19114             this.familyName = parts.join('');
19115         } else {
19116             this.givenName = parts.join('');
19117         }
19118     },
19119 
19120     /**
19121      * @protected
19122      */
19123     _parseKoreanName: function (name) {
19124         var tempName = name;
19125 
19126         var spaceSplit = tempName.split(" ");
19127         var spceCount = spaceSplit.length;
19128         var fistSpaceIndex = tempName.indexOf(" ");
19129         var lastSpaceIndex = tempName.lastIndexOf(" ");
19130 
19131         if (spceCount === 2) {
19132             this.familyName = spaceSplit[0];
19133             this.givenName = tempName.slice(fistSpaceIndex, tempName.length);
19134         } else {
19135             this.familyName = spaceSplit[0];
19136             this.middleName = tempName.slice(fistSpaceIndex, lastSpaceIndex);
19137             this.givenName = tempName.slice(lastSpaceIndex, tempName.length);
19138         }
19139         
19140     },
19141 
19142     /**
19143      * @protected
19144      */
19145     _parseJapaneseName: function (parts) {
19146     	if (this.suffix && this.suffix.length > 1 && this.info.honorifics.indexOf(this.suffix)>-1) {
19147     		if (parts.length === 1) {
19148     			if (ilib.CType.withinRange(parts[0], "cjk")) {
19149     				this.familyName = parts[0];
19150     			} else {
19151     				this.givenName = parts[0];
19152     			}
19153     			return;
19154     		} else if (parts.length === 2) {
19155     			this.familyName = parts.slice(0,parts.length).join("")
19156     			return;
19157     		}
19158     	}
19159     	if (parts.length > 1) {
19160     		var fn = "";                                                                    
19161     		for (var i = 0; i < parts.length; i++) {
19162     			if (ilib.CType.withinRange(parts[i], "cjk")) {
19163     				fn += parts[i];
19164     			} else if (fn.length > 1 && ilib.CType.withinRange(parts[i], "hiragana")) {
19165     				this.familyName = fn;
19166     				this.givenName = parts.slice(i,parts.length).join("");
19167     				return;
19168     			} else {
19169     				break;
19170     			}
19171     		}
19172     	}
19173     	if (parts.length === 1) {
19174     		this.familyName = parts[0];
19175     	} else if (parts.length === 2) {
19176     		this.familyName = parts[0];
19177     		this.givenName = parts[1];
19178     	} else if (parts.length === 3) {
19179     		this.familyName = parts[0];
19180     		this.givenName = parts.slice(1,parts.length).join("");
19181     	} else if (parts.length > 3) {
19182     		this.familyName = parts.slice(0,2).join("")
19183     		this.givenName = parts.slice(2,parts.length).join("");
19184     	}      
19185     },
19186 
19187     /**
19188      * @protected
19189      */
19190     _parseSpanishName: function (parts) {
19191         var conjunctionIndex;
19192 
19193         if (parts.length === 1) {
19194             if (this.prefix || typeof (parts[0]) === 'object') {
19195                 this.familyName = parts[0];
19196             } else {
19197                 this.givenName = parts[0];
19198             }
19199         } else if (parts.length === 2) {
19200             // we do G F
19201             this.givenName = parts[0];
19202             this.familyName = parts[1];
19203         } else if (parts.length === 3) {
19204             conjunctionIndex = this._findLastConjunction(parts);
19205             // if there's an 'and' in the middle spot, put everything in the first name
19206             if (conjunctionIndex === 1) {
19207                 this.givenName = parts;
19208             } else {
19209                 // else, do G F F
19210                 this.givenName = parts[0];
19211                 this.familyName = parts.slice(1);
19212             }
19213         } else if (parts.length > 3) {
19214             //there are at least 4 parts to this name
19215 
19216             conjunctionIndex = this._findLastConjunction(parts);
19217             ////console.log("@@@@@@@@@@@@@@@@"+conjunctionIndex)
19218             if (conjunctionIndex > 0) {
19219                 // if there's a conjunction that's not the first token, put everything up to and 
19220                 // including the token after it into the first name, the last 2 tokens into
19221                 // the family name (if they exist) and everything else in to the middle name
19222                 // 0 1 2 3 4 5
19223                 // G A G
19224                 // G A G F
19225                 // G G A G
19226                 // G A G F F
19227                 // G G A G F
19228                 // G G G A G
19229                 // G A G M F F
19230                 // G G A G F F
19231                 // G G G A G F
19232                 // G G G G A G
19233                 this.givenName = parts.splice(0, conjunctionIndex + 2);
19234                 if (parts.length > 1) {
19235                     this.familyName = parts.splice(parts.length - 2, 2);
19236                     if (parts.length > 0) {
19237                         this.middleName = parts;
19238                     }
19239                 } else if (parts.length === 1) {
19240                     this.familyName = parts[0];
19241                 }
19242             } else {
19243                 this.givenName = parts.splice(0, 1);
19244                 this.familyName = parts.splice(parts.length - 2, 2);
19245                 this.middleName = parts;
19246             }
19247         }
19248     },
19249 
19250     /**
19251      * @protected
19252      */
19253     _parseIndonesianName: function (parts) {
19254         var conjunctionIndex;
19255 
19256         if (parts.length === 1) {
19257             //if (this.prefix || typeof(parts[0]) === 'object') {
19258             //this.familyName = parts[0];
19259             //} else {
19260             this.givenName = parts[0];
19261             //}
19262             //} else if (parts.length === 2) {
19263             // we do G F
19264             //this.givenName = parts[0];
19265             //this.familyName = parts[1];
19266         } else if (parts.length >= 2) {
19267             //there are at least 3 parts to this name
19268 
19269             conjunctionIndex = this._findLastConjunction(parts);
19270             if (conjunctionIndex > 0) {
19271                 // if there's a conjunction that's not the first token, put everything up to and 
19272                 // including the token after it into the first name, the last 2 tokens into
19273                 // the family name (if they exist) and everything else in to the middle name
19274                 // 0 1 2 3 4 5
19275                 // G A G
19276                 // G A G F
19277                 // G G A G
19278                 // G A G F F
19279                 // G G A G F
19280                 // G G G A G
19281                 // G A G M F F
19282                 // G G A G F F
19283                 // G G G A G F
19284                 // G G G G A G
19285                 this.givenName = parts.splice(0, conjunctionIndex + 2);
19286                 if (parts.length > 1) {
19287                     //this.familyName = parts.splice(parts.length-2, 2);
19288                     //if ( parts.length > 0 ) {
19289                     this.middleName = parts;
19290                 }
19291                 //} else if (parts.length === 1) {
19292                 //	this.familyName = parts[0];
19293                 //}
19294             } else {
19295                 this.givenName = parts.splice(0, 1);
19296                 //this.familyName = parts.splice(parts.length-2, 2);
19297                 this.middleName = parts;
19298             }
19299         }
19300     },
19301     
19302     /**
19303      * @protected
19304      */
19305     _parseGenericWesternName: function (parts) {
19306         /* Western names are parsed as follows, and rules are applied in this 
19307          * order:
19308          *
19309          * G
19310          * G F
19311          * G M F
19312          * G M M F
19313          * P F
19314          * P G F
19315          */
19316         var conjunctionIndex;
19317 
19318         if (parts.length === 1) {
19319             if (this.prefix || typeof (parts[0]) === 'object') {
19320                 // already has a prefix, so assume it goes with the family name like "Dr. Roberts" or
19321                 // it is a name with auxillaries, which is almost always a family name
19322                 this.familyName = parts[0];
19323             } else {
19324                 this.givenName = parts[0];
19325             }
19326         } else if (parts.length === 2) {
19327             // we do G F
19328             if (this.info.order == 'fgm') {
19329                 this.givenName = parts[1];
19330                 this.familyName = parts[0];
19331             } else if (this.info.order == "gmf" || typeof (this.info.order) == 'undefined') {
19332                 this.givenName = parts[0];
19333                 this.familyName = parts[1];
19334             }
19335         } else if (parts.length >= 3) {
19336             //find the first instance of 'and' in the name
19337             conjunctionIndex = this._findLastConjunction(parts);
19338 
19339             if (conjunctionIndex > 0) {
19340                 // if there's a conjunction that's not the first token, put everything up to and 
19341                 // including the token after it into the first name, the last token into
19342                 // the family name (if it exists) and everything else in to the middle name
19343                 // 0 1 2 3 4 5
19344                 // G A G M M F
19345                 // G G A G M F
19346                 // G G G A G F
19347                 // G G G G A G
19348                 //if(this.order == "gmf") {
19349                 this.givenName = parts.slice(0, conjunctionIndex + 2);
19350 
19351                 if (conjunctionIndex + 1 < parts.length - 1) {
19352                     this.familyName = parts.splice(parts.length - 1, 1);
19353                     ////console.log(this.familyName);
19354                     if (conjunctionIndex + 2 < parts.length - 1) {
19355                         this.middleName = parts.slice(conjunctionIndex + 2, parts.length - conjunctionIndex - 3);
19356                     }
19357                 } else if (this.order == "fgm") {
19358                     this.familyName = parts.slice(0, conjunctionIndex + 2);
19359                     if (conjunctionIndex + 1 < parts.length - 1) {
19360                         this.middleName = parts.splice(parts.length - 1, 1);
19361                         if (conjunctionIndex + 2 < parts.length - 1) {
19362                             this.givenName = parts.slice(conjunctionIndex + 2, parts.length - conjunctionIndex - 3);
19363                         }
19364                     }
19365                 }
19366             } else {
19367                 this.givenName = parts[0];
19368 
19369                 this.middleName = parts.slice(1, parts.length - 1);
19370 
19371                 this.familyName = parts[parts.length - 1];
19372             }
19373         }
19374     },
19375     
19376      /**
19377      * parse patrinomic name from the russian names 
19378      * @protected
19379      * @param {Array.<string>} parts the current array of name parts
19380      * @return number  index of the part which contains patronymic name
19381      */
19382     _findPatronymicName: function(parts) {
19383     	var index, part;
19384     	for (index = 0; index < parts.length; index++) {
19385     		part = parts[index];
19386     		if (typeof (part) === 'string') {
19387     			part = part.toLowerCase();
19388 
19389     			var subLength = this.info.patronymicName.length;
19390     			while(subLength--) {
19391     				if(part.indexOf(this.info.patronymicName[subLength])!== -1 )
19392     					return index;
19393     			}
19394     		}
19395     	}
19396     	return -1;
19397     },
19398 
19399     /**
19400 	 * find if the given part is patronymic name
19401 	 * 
19402 	 * @protected
19403 	 * @param {string} part string from name parts @
19404 	 * @return number index of the part which contains familyName
19405 	 */
19406     _isPatronymicName: function(part) {
19407 	    var pName;
19408 	    if ( typeof (part) === 'string') {
19409 		    pName = part.toLowerCase();
19410 
19411 		    var subLength = this.info.patronymicName.length;
19412 		    while (subLength--) {
19413 			    if (pName.indexOf(this.info.patronymicName[subLength]) !== -1)
19414 				    return true;
19415 		    }
19416 	    }
19417 	    return false;
19418     },
19419 
19420     /**
19421 	 * find family name from the russian name
19422 	 * 
19423 	 * @protected
19424 	 * @param {Array.<string>} parts the current array of name parts
19425 	 * @return boolean true if patronymic, false otherwise
19426 	 */
19427     _findFamilyName: function(parts) {
19428 	    var index, part, substring;
19429 	    for (index = 0; index < parts.length; index++) {
19430 		    part = parts[index];
19431 
19432 		    if ( typeof (part) === 'string') {
19433 			    part = part.toLowerCase();
19434 			    var length = part.length - 1;
19435 
19436 			    if (this.info.familyName.indexOf(part) !== -1) {
19437 				    return index;
19438 			    } else if (part[length] === 'в' || part[length] === 'н' ||
19439 			        part[length] === 'й') {
19440 				    substring = part.slice(0, -1);
19441 				    if (this.info.familyName.indexOf(substring) !== -1) {
19442 					    return index;
19443 				    }
19444 			    } else if ((part[length - 1] === 'в' && part[length] === 'а') ||
19445 			        (part[length - 1] === 'н' && part[length] === 'а') ||
19446 			        (part[length - 1] === 'а' && part[length] === 'я')) {
19447 				    substring = part.slice(0, -2);
19448 				    if (this.info.familyName.indexOf(substring) !== -1) {
19449 					    return index;
19450 				    }
19451 			    }
19452 		    }
19453 	    }
19454 	    return -1;
19455     },
19456 
19457     /**
19458 	 * parse russian name
19459 	 * 
19460 	 * @protected
19461 	 * @param {Array.<string>} parts the current array of name parts
19462 	 * @return
19463 	 */
19464     _parseRussianName: function(parts) {
19465 	    var conjunctionIndex, familyIndex = -1;
19466 
19467 	    if (parts.length === 1) {
19468 		    if (this.prefix || typeof (parts[0]) === 'object') {
19469 			    // already has a prefix, so assume it goes with the family name
19470 				// like "Dr. Roberts" or
19471 			    // it is a name with auxillaries, which is almost always a
19472 				// family name
19473 			    this.familyName = parts[0];
19474 		    } else {
19475 			    this.givenName = parts[0];
19476 		    }
19477 	    } else if (parts.length === 2) {
19478 		    // we do G F
19479 		    if (this.info.order === 'fgm') {
19480 			    this.givenName = parts[1];
19481 			    this.familyName = parts[0];
19482 		    } else if (this.info.order === "gmf") {
19483 			    this.givenName = parts[0];
19484 			    this.familyName = parts[1];
19485 		    } else if ( typeof (this.info.order) === 'undefined') {
19486 			    if (this._isPatronymicName(parts[1]) === true) {
19487 				    this.middleName = parts[1];
19488 				    this.givenName = parts[0];
19489 			    } else if ((familyIndex = this._findFamilyName(parts)) !== -1) {
19490 				    if (familyIndex === 1) {
19491 					    this.givenName = parts[0];
19492 					    this.familyName = parts[1];
19493 				    } else {
19494 					    this.familyName = parts[0];
19495 					    this.givenName = parts[1];
19496 				    }
19497 
19498 			    } else {
19499 				    this.givenName = parts[0];
19500 				    this.familyName = parts[1];
19501 			    }
19502 
19503 		    }
19504 	    } else if (parts.length >= 3) {
19505 		    // find the first instance of 'and' in the name
19506 		    conjunctionIndex = this._findLastConjunction(parts);
19507 		    var patronymicNameIndex = this._findPatronymicName(parts);
19508 		    if (conjunctionIndex > 0) {
19509 			    // if there's a conjunction that's not the first token, put
19510 				// everything up to and
19511 			    // including the token after it into the first name, the last
19512 				// token into
19513 			    // the family name (if it exists) and everything else in to the
19514 				// middle name
19515 			    // 0 1 2 3 4 5
19516 			    // G A G M M F
19517 			    // G G A G M F
19518 			    // G G G A G F
19519 			    // G G G G A G
19520 			    // if(this.order == "gmf") {
19521 			    this.givenName = parts.slice(0, conjunctionIndex + 2);
19522 
19523 			    if (conjunctionIndex + 1 < parts.length - 1) {
19524 				    this.familyName = parts.splice(parts.length - 1, 1);
19525 				    // //console.log(this.familyName);
19526 				    if (conjunctionIndex + 2 < parts.length - 1) {
19527 					    this.middleName = parts.slice(conjunctionIndex + 2,
19528 					        parts.length - conjunctionIndex - 3);
19529 				    }
19530 			    } else if (this.order == "fgm") {
19531 				    this.familyName = parts.slice(0, conjunctionIndex + 2);
19532 				    if (conjunctionIndex + 1 < parts.length - 1) {
19533 					    this.middleName = parts.splice(parts.length - 1, 1);
19534 					    if (conjunctionIndex + 2 < parts.length - 1) {
19535 						    this.givenName = parts.slice(conjunctionIndex + 2,
19536 						        parts.length - conjunctionIndex - 3);
19537 					    }
19538 				    }
19539 			    }
19540 		    } else if (patronymicNameIndex !== -1) {
19541 			    this.middleName = parts[patronymicNameIndex];
19542 
19543 			    if (patronymicNameIndex === (parts.length - 1)) {
19544 				    this.familyName = parts[0];
19545 				    this.givenName = parts.slice(1, patronymicNameIndex);
19546 			    } else {
19547 				    this.givenName = parts.slice(0, patronymicNameIndex);
19548 
19549 				    this.familyName = parts[parts.length - 1];
19550 			    }
19551 		    } else {
19552 			    this.givenName = parts[0];
19553 
19554 			    this.middleName = parts.slice(1, parts.length - 1);
19555 
19556 			    this.familyName = parts[parts.length - 1];
19557 		    }
19558 	    }
19559     },
19560     
19561     
19562     /**
19563      * @protected
19564      */
19565     _parseWesternName: function (parts) {
19566 
19567         if (this.locale.getLanguage() === "es" || this.locale.getLanguage() === "pt") {
19568             // in spain and mexico and portugal, we parse names differently than in the rest of the world 
19569             // because of the double family names
19570             this._parseSpanishName(parts);
19571         } else if (this.locale.getLanguage() === "ru") {
19572             /*
19573              * In Russian, names can be given equally validly as given-family
19574              * or family-given. Use the value of the "order" property of the
19575              * constructor options to give the default when the order is ambiguous.
19576              */
19577             this._parseRussianName(parts);
19578         } else if (this.locale.getLanguage() === "id") {
19579             // in indonesia, we parse names differently than in the rest of the world 
19580             // because names don't have family names usually.
19581             this._parseIndonesianName(parts);
19582         } else {
19583         	this._parseGenericWesternName(parts);
19584         }
19585     },
19586 
19587     /**
19588      * When sorting names with auxiliary words (like "van der" or "de los"), determine
19589      * which is the "head word" and return a string that can be easily sorted by head
19590      * word. In English, names are always sorted by initial characters. In places like
19591      * the Netherlands or Germany, family names are sorted by the head word of a list
19592      * of names rather than the first element of that name.
19593      * @return {string|undefined} a string containing the family name[s] to be used for sorting
19594      * in the current locale, or undefined if there is no family name in this object
19595      */
19596     getSortFamilyName: function () {
19597         var name,
19598             auxillaries,
19599             auxString,
19600             parts,
19601             i;
19602 
19603         // no name to sort by
19604         if (!this.familyName) {
19605             return undefined;
19606         }
19607 
19608         // first break the name into parts
19609         if (this.info) {
19610             if (this.info.sortByHeadWord) {
19611                 if (typeof (this.familyName) === 'string') {
19612                     name = this.familyName.replace(/\s+/g, ' '); // compress multiple whitespaces
19613                     parts = name.trim().split(' ');
19614                 } else {
19615                     // already split
19616                     parts = /** @type Array */ this.familyName;
19617                 }
19618 
19619                 auxillaries = this._findPrefix(parts, this.info.auxillaries, false);
19620                 if (auxillaries && auxillaries.length > 0) {
19621                     if (typeof (this.familyName) === 'string') {
19622                         auxString = auxillaries.join(' ');
19623                         name = this.familyName.substring(auxString.length + 1) + ', ' + auxString;
19624                     } else {
19625                         name = parts.slice(auxillaries.length).join(' ') +
19626                             ', ' +
19627                             parts.slice(0, auxillaries.length).join(' ');
19628                     }
19629                 }
19630             } else if (this.info.knownFamilyNames && this.familyName) {
19631                 parts = this.familyName.split('');
19632                 var familyNameArray = this._findPrefix(parts, this.info.knownFamilyNames, true, this.info.noCompoundFamilyNames);
19633                 name = "";
19634                 for (i = 0; i < familyNameArray.length; i++) {
19635                     name += (this.info.knownFamilyNames[familyNameArray[i]] || "");
19636                 }
19637             }
19638         }
19639 
19640         return name || this.familyName;
19641     },
19642 
19643     getHeadFamilyName: function () {},
19644 
19645     /** 
19646      * @protected
19647      * Return a shallow copy of the current instance.
19648      */
19649     clone: function () {
19650         return new ilib.Name(this);
19651     }
19652 };
19653 
19654 /*
19655  * namefmt.js - Format person names for display
19656  * 
19657  * Copyright © 2013-2014, JEDLSoft
19658  *
19659  * Licensed under the Apache License, Version 2.0 (the "License");
19660  * you may not use this file except in compliance with the License.
19661  * You may obtain a copy of the License at
19662  *
19663  *     http://www.apache.org/licenses/LICENSE-2.0
19664  *
19665  * Unless required by applicable law or agreed to in writing, software
19666  * distributed under the License is distributed on an "AS IS" BASIS,
19667  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19668  *
19669  * See the License for the specific language governing permissions and
19670  * limitations under the License.
19671  */
19672 
19673 /* !depends 
19674 ilibglobal.js
19675 locale.js
19676 strings.js
19677 nameprs.js
19678 ctype.ispunct.js
19679 */
19680 
19681 // !data name
19682 
19683 /**
19684  * @class
19685  * Creates a formatter that can format person name instances (ilib.Name) for display to
19686  * a user. The options may contain the following properties:
19687  * 
19688  * <ul>
19689  * <li><i>locale</i> - Use the conventions of the given locale to construct the name format. 
19690  * <li><i>style</i> - Format the name with the given style. The value of this property
19691  * should be one of the following strings: 
19692  *   <ul>
19693  *     <li><i>short</i> - Format a short name with just the given and family names.
19694  *     <li><i>medium</i> - Format a medium-length name with the given, middle, and family names.
19695  *     <li><i>long</i> - Format a long name with all names available in the given name object, including
19696  *     prefixes.
19697  *     <li><i>full</i> - Format a long name with all names available in the given name object, including
19698  *     prefixes and suffixes.
19699  *   </ul>
19700  * <li><i>components</i> - Format the name with the given components in the correct
19701  * order for those components. Components are encoded as a string of letters representing
19702  * the desired components:
19703  *   <ul>
19704  *     <li><i>p</i> - prefixes
19705  *     <li><i>g</i> - given name
19706  *     <li><i>m</i> - middle names
19707  *     <li><i>f</i> - family name
19708  *     <li><i>s</i> - suffixes
19709  *   </ul>
19710  * <p>
19711  * 
19712  * For example, the string "pf" would mean to only format any prefixes and family names 
19713  * together and leave out all the other parts of the name.<p>
19714  * 
19715  * The components can be listed in any order in the string. The <i>components</i> option 
19716  * overrides the <i>style</i> option if both are specified.
19717  *
19718  * <li>onLoad - a callback function to call when the locale info object is fully 
19719  * loaded. When the onLoad option is given, the localeinfo object will attempt to
19720  * load any missing locale data using the ilib loader callback.
19721  * When the constructor is done (even if the data is already preassembled), the 
19722  * onLoad function is called with the current instance as a parameter, so this
19723  * callback can be used with preassembled or dynamic loading or a mix of the two.
19724  * 
19725  * <li>sync - tell whether to load any missing locale data synchronously or 
19726  * asynchronously. If this option is given as "false", then the "onLoad"
19727  * callback must be given, as the instance returned from this constructor will
19728  * not be usable for a while. 
19729  *
19730  * <li><i>loadParams</i> - an object containing parameters to pass to the 
19731  * loader callback function when locale data is missing. The parameters are not
19732  * interpretted or modified in any way. They are simply passed along. The object 
19733  * may contain any property/value pairs as long as the calling code is in
19734  * agreement with the loader callback function as to what those parameters mean.
19735  * </ul>
19736  * 
19737  * Formatting names is a locale-dependent function, as the order of the components 
19738  * depends on the locale. The following explains some of the details:<p>
19739  * 
19740  * <ul>
19741  * <li>In Western countries, the given name comes first, followed by a space, followed 
19742  * by the family name. In Asian countries, the family name comes first, followed immediately
19743  * by the given name with no space. But, that format is only used with Asian names written
19744  * in ideographic characters. In Asian countries, especially ones where both an Asian and 
19745  * a Western language are used (Hong Kong, Singapore, etc.), the convention is often to 
19746  * follow the language of the name. That is, Asian names are written in Asian style, and 
19747  * Western names are written in Western style. This class follows that convention as
19748  * well. 
19749  * <li>In other Asian countries, Asian names
19750  * written in Latin script are written with Asian ordering. eg. "Xu Ping-an" instead
19751  * of the more Western order "Ping-an Xu", as the order is thought to go with the style
19752  * that is appropriate for the name rather than the style for the language being written.
19753  * <li>In some Spanish speaking countries, people often take both their maternal and
19754  * paternal last names as their own family name. When formatting a short or medium style
19755  * of that family name, only the paternal name is used. In the long style, all the names
19756  * are used. eg. "Juan Julio Raul Lopez Ortiz" took the name "Lopez" from his father and 
19757  * the name "Ortiz" from his mother. His family name would be "Lopez Ortiz". The formatted
19758  * short style of his name would be simply "Juan Lopez" which only uses his paternal
19759  * family name of "Lopez".
19760  * <li>In many Western languages, it is common to use auxillary words in family names. For
19761  * example, the family name of "Ludwig von Beethoven" in German is "von Beethoven", not 
19762  * "Beethoven". This class ensures that the family name is formatted correctly with 
19763  * all auxillary words.   
19764  * </ul>
19765  * 
19766  * Depends directive: !depends namefmt.js
19767  * 
19768  * @constructor
19769  * @param {Object} options A set of options that govern how the formatter will behave
19770  */
19771 ilib.NameFmt = function(options) {
19772 	var sync = true;
19773 	
19774 	this.style = "short";
19775 	this.loadParams = {};
19776 	
19777 	if (options) {
19778 		if (options.locale) {
19779 			this.locale = (typeof(options.locale) === 'string') ? new ilib.Locale(options.locale) : options.locale;
19780 		}
19781 		
19782 		if (options.style) {
19783 			this.style = options.style;
19784 		}
19785 		
19786 		if (options.components) {
19787 			this.components = options.components;
19788 		}
19789 		
19790 		if (typeof(options.sync) !== 'undefined') {
19791 			sync = (options.sync == true);
19792 		}
19793 		
19794 		if (typeof(options.loadParams) !== 'undefined') {
19795 			this.loadParams = options.loadParams;
19796 		}
19797 	}
19798 	
19799 	// set up defaults in case we need them
19800 	this.defaultEuroTemplate = new ilib.String("{prefix} {givenName} {middleName} {familyName}{suffix}");
19801 	this.defaultAsianTemplate = new ilib.String("{prefix}{familyName}{givenName}{middleName}{suffix}");
19802 	this.useFirstFamilyName = false;
19803 
19804 	switch (this.style) {
19805 		default:
19806 		case "s":
19807 		case "short":
19808 			this.style = "short";
19809 			break;
19810 		case "m":
19811 		case "medium":
19812 			this.style = "medium";
19813 			break;
19814 		case "l":
19815 		case "long":
19816 			this.style = "long";
19817 			break;
19818 		case "f":
19819 		case "full":
19820 			this.style = "full";
19821 			break;
19822 	}
19823 
19824 	if (!ilib.Name.cache) {
19825 		ilib.Name.cache = {};
19826 	}
19827 
19828 	this.locale = this.locale || new ilib.Locale();
19829 	
19830 	ilib.CType.isPunct._init(sync, this.loadParams, /** @type {function()|undefined} */ ilib.bind(this, function() {
19831 		ilib.loadData({
19832 			object: ilib.Name, 
19833 			locale: this.locale, 
19834 			name: "name.json", 
19835 			sync: sync, 
19836 			loadParams: this.loadParams, 
19837 			callback: ilib.bind(this, function (info) {
19838 				if (!info) {
19839 					info = ilib.Name.defaultInfo;
19840 					var spec = this.locale.getSpec().replace(/-/g, "_");
19841 					ilib.Name.cache[spec] = info;
19842 				}
19843 				this.info = info;
19844 				this._init();
19845 				if (options && typeof(options.onLoad) === 'function') {
19846 					options.onLoad(this);
19847 				}
19848 			})
19849 		});
19850 	}));
19851 };
19852 
19853 ilib.NameFmt.prototype = {
19854 	/**                          
19855 	 * @protected
19856 	 */
19857 	_init: function() {
19858 		if (this.components) {
19859 			var valids = {"p":1,"g":1,"m":1,"f":1,"s":1},
19860 				arr = this.components.split("");
19861 			this.comps = {};
19862 			for (var i = 0; i < arr.length; i++) {
19863 				if (valids[arr[i].toLowerCase()]) {
19864 					this.comps[arr[i].toLowerCase()] = true;
19865 				}
19866 			}
19867 		} else {
19868 			this.comps = this.info.components[this.style];
19869 		}
19870 
19871 		this.template = new ilib.String(this.info.format);
19872 		
19873 		if (this.locale.language === "es" && (this.style !== "long" && this.style !== "full")) {
19874 			this.useFirstFamilyName = true;	// in spanish, they have 2 family names, the maternal and paternal
19875 		}
19876 
19877 		this.isAsianLocale = (this.info.nameStyle === "asian");
19878 	},
19879 
19880 	/**
19881 	 * adjoin auxillary words to their head words
19882 	 * @protected
19883 	 */
19884 	_adjoinAuxillaries: function (parts, namePrefix) {
19885 		var start, i, prefixArray, prefix, prefixLower;
19886 		
19887 		//console.info("_adjoinAuxillaries: finding and adjoining aux words in " + parts.join(' '));
19888 		
19889 		if ( this.info.auxillaries && (parts.length > 2 || namePrefix) ) {
19890 			for ( start = 0; start < parts.length-1; start++ ) {
19891 				for ( i = parts.length; i > start; i-- ) {
19892 					prefixArray = parts.slice(start, i);
19893 					prefix = prefixArray.join(' ');
19894 					prefixLower = prefix.toLowerCase();
19895 					prefixLower = prefixLower.replace(/[,\.]/g, '');  // ignore commas and periods
19896 					
19897 					//console.info("_adjoinAuxillaries: checking aux prefix: '" + prefixLower + "' which is " + start + " to " + i);
19898 					
19899 					if ( prefixLower in this.info.auxillaries ) {
19900 						//console.info("Found! Old parts list is " + JSON.stringify(parts));
19901 						parts.splice(start, i+1-start, prefixArray.concat(parts[i]));
19902 						//console.info("_adjoinAuxillaries: Found! New parts list is " + JSON.stringify(parts));
19903 						i = start;
19904 					}
19905 				}
19906 			}
19907 		}
19908 		
19909 		//console.info("_adjoinAuxillaries: done. Result is " + JSON.stringify(parts));
19910 
19911 		return parts;
19912 	},
19913 
19914 	/**
19915 	 * Return the locale for this formatter instance.
19916 	 * @return {ilib.Locale} the locale instance for this formatter
19917 	 */
19918 	getLocale: function () {
19919 		return this.locale;
19920 	},
19921 	
19922 	/**
19923 	 * Return the style of names returned by this formatter
19924 	 * @return {string} the style of names returned by this formatter
19925 	 */
19926 	getStyle: function () {
19927 		return this.style;
19928 	},
19929 	
19930 	/**
19931 	 * Return the list of components used to format names in this formatter
19932 	 * @return {string} the list of components
19933 	 */
19934 	getComponents: function () {
19935 		return this.components;
19936 	},
19937 	
19938 	/**
19939 	 * Format the name for display in the current locale with the options set up
19940 	 * in the constructor of this formatter instance.<p>
19941 	 * 
19942 	 * If the name does not contain all the parts required for the style, those parts
19943 	 * will be left blank.<p>
19944 	 * 
19945 	 * There are two basic styles of formatting: European, and Asian. If this formatter object
19946 	 * is set for European style, but an Asian name is passed to the format method, then this
19947 	 * method will format the Asian name with a generic Asian template. Similarly, if the
19948 	 * formatter is set for an Asian style, and a European name is passed to the format method,
19949 	 * the formatter will use a generic European template.<p>
19950 	 * 
19951 	 * This means it is always safe to format any name with a formatter for any locale. You should
19952 	 * always get something at least reasonable as output.<p>
19953 	 * 
19954 	 * @param {ilib.Name} name the name to format
19955 	 * @return {string|undefined} the name formatted according to the style of this formatter instance
19956 	 */
19957 	format: function(name) {
19958 		var formatted, temp, modified, isAsianName;
19959 		var currentLanguage = this.locale.getLanguage();
19960 		 
19961 		if (!name || typeof(name) !== 'object') {
19962 			return undefined;
19963 		}
19964 		
19965 		if ((typeof(name.isAsianName) === 'boolean' && !name.isAsianName) ||
19966 				ilib.Name._isEuroName([name.givenName, name.middleName, name.familyName].join(""), currentLanguage)) {
19967 			isAsianName = false;	// this is a euro name, even if the locale is asian
19968 			modified = name.clone();
19969 			
19970 			// handle the case where there is no space if there is punctuation in the suffix like ", Phd". 
19971 			// Otherwise, put a space in to transform "PhD" to " PhD"
19972 			/*
19973 			console.log("suffix is " + modified.suffix);
19974 			if ( modified.suffix ) {
19975 				console.log("first char is " + modified.suffix.charAt(0));
19976 				console.log("isPunct(modified.suffix.charAt(0)) is " + ilib.CType.isPunct(modified.suffix.charAt(0)));
19977 			}
19978 			*/
19979 			if (modified.suffix && ilib.CType.isPunct(modified.suffix.charAt(0)) === false) {
19980 				modified.suffix = ' ' + modified.suffix; 
19981 			}
19982 			
19983 			if (this.useFirstFamilyName && name.familyName) {
19984 				var familyNameParts = modified.familyName.trim().split(' ');
19985 				if (familyNameParts.length > 1) {
19986 					familyNameParts = this._adjoinAuxillaries(familyNameParts, name.prefix);
19987 				}	//in spain and mexico, we parse names differently than in the rest of the world
19988 	
19989 				modified.familyName = familyNameParts[0];
19990 			}
19991 		
19992 			modified._joinNameArrays();
19993 		} else {
19994 			isAsianName = true;
19995 			modified = name;
19996 			if (modified.suffix && currentLanguage === "ko" && this.info.honorifics.indexOf(name.suffix) == -1) {
19997 				modified.suffix = ' ' + modified.suffix; 
19998 			}
19999 		}
20000 		
20001 		if (!this.template || isAsianName !== this.isAsianLocale) {
20002 			temp = isAsianName ? this.defaultAsianTemplate : this.defaultEuroTemplate;
20003 		} else {
20004 			temp = this.template;
20005 		}
20006 		
20007 		var parts = {
20008 			prefix: this.comps["p"] && modified.prefix || "",
20009 			givenName: this.comps["g"] && modified.givenName || "",
20010 			middleName: this.comps["m"] && modified.middleName || "",
20011 			familyName: this.comps["f"] && modified.familyName || "",
20012 			suffix: this.comps["s"] && modified.suffix || ""
20013 		};
20014 		
20015 		formatted = temp.format(parts);
20016 		return formatted.replace(/\s+/g, ' ').trim();
20017 	}
20018 };
20019 
20020 /**
20021  * addressprs.js - Represent a mailing address
20022  * 
20023  * Copyright © 2013-2014, JEDLSoft
20024  *
20025  * Licensed under the Apache License, Version 2.0 (the "License");
20026  * you may not use this file except in compliance with the License.
20027  * You may obtain a copy of the License at
20028  *
20029  *     http://www.apache.org/licenses/LICENSE-2.0
20030  *
20031  * Unless required by applicable law or agreed to in writing, software
20032  * distributed under the License is distributed on an "AS IS" BASIS,
20033  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20034  *
20035  * See the License for the specific language governing permissions and
20036  * limitations under the License.
20037  */
20038 
20039 /*globals console RegExp */
20040 
20041 /* !depends 
20042 ilibglobal.js 
20043 locale.js 
20044 ctype.isideo.js 
20045 ctype.isascii.js
20046 ctype.isdigit.js
20047 */
20048 
20049 // !data address countries nativecountries ctrynames
20050 
20051 /**
20052  * @class
20053  * Create a new Address instance and parse a physical address.<p>
20054  * 
20055  * This function parses a physical address written in a free-form string. 
20056  * It returns an object with a number of properties from the list below 
20057  * that it may have extracted from that address.<p>
20058  * 
20059  * The following is a list of properties that the algorithm will return:<p>
20060  * 
20061  * <ul>
20062  * <li><i>streetAddress</i>: The street address, including house numbers and all.
20063  * <li><i>locality</i>: The locality of this address (usually a city or town). 
20064  * <li><i>region</i>: The region where the locality is located. In the US, this
20065  * corresponds to states. In other countries, this may be provinces,
20066  * cantons, prefectures, etc. In some smaller countries, there are no
20067  * such divisions.
20068  * <li><i>postalCode</i>: Country-specific code for expediting mail. In the US, 
20069  * this is the zip code.
20070  * <li><i>country</i>: The country of the address.
20071  * <li><i>countryCode</i>: The ISO 3166 2-letter region code for the destination
20072  * country in this address.
20073  * </ul> 
20074  * 
20075  * The above properties will not necessarily appear in the instance. For 
20076  * any individual property, if the free-form address does not contain 
20077  * that property or it cannot be parsed out, the it is left out.<p>
20078  * 
20079  * The options parameter may contain any of the following properties:
20080  * 
20081  * <ul>
20082  * <li><i>locale</i> - locale or localeSpec to use to parse the address. If not 
20083  * specified, this function will use the current ilib locale
20084  * 
20085  * <li><i>onLoad</i> - a callback function to call when the address info for the
20086  * locale is fully loaded and the address has been parsed. When the onLoad 
20087  * option is given, the address object 
20088  * will attempt to load any missing locale data using the ilib loader callback.
20089  * When the constructor is done (even if the data is already preassembled), the 
20090  * onLoad function is called with the current instance as a parameter, so this
20091  * callback can be used with preassembled or dynamic loading or a mix of the two. 
20092  * 
20093  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
20094  * asynchronously. If this option is given as "false", then the "onLoad"
20095  * callback must be given, as the instance returned from this constructor will
20096  * not be usable for a while. 
20097  *
20098  * <li><i>loadParams</i> - an object containing parameters to pass to the 
20099  * loader callback function when locale data is missing. The parameters are not
20100  * interpretted or modified in any way. They are simply passed along. The object 
20101  * may contain any property/value pairs as long as the calling code is in
20102  * agreement with the loader callback function as to what those parameters mean.
20103  * </ul>
20104  * 
20105  * When an address cannot be parsed properly, the entire address will be placed
20106  * into the streetAddress property.<p>
20107  * 
20108  * When the freeformAddress is another ilib.Address, this will act like a copy
20109  * constructor.<p>
20110  * 
20111  * Depends directive: !depends addressprs.js
20112  * 
20113  * @constructor
20114  * @param {string|ilib.Address} freeformAddress free-form address to parse, or a
20115  * javascript object containing the fields
20116  * @param {Object} options options to the parser
20117  */
20118 ilib.Address = function (freeformAddress, options) {
20119 	var address;
20120 
20121 	if (!freeformAddress) {
20122 		return undefined;
20123 	}
20124 
20125 	this.sync = true;
20126 	this.loadParams = {};
20127 	
20128 	if (options) {
20129 		if (options.locale) {
20130 			this.locale = (typeof(options.locale) === 'string') ? new ilib.Locale(options.locale) : options.locale;
20131 		}
20132 		
20133 		if (typeof(options.sync) !== 'undefined') {
20134 			this.sync = (options.sync == true);
20135 		}
20136 		
20137 		if (options.loadParams) {
20138 			this.loadParams = options.loadParams;
20139 		}
20140 	}
20141 
20142 	this.locale = this.locale || new ilib.Locale();
20143 	// initialize from an already parsed object
20144 	if (typeof(freeformAddress) === 'object') {
20145 		/**
20146 		 * The street address, including house numbers and all.
20147 		 * @expose
20148 		 * @type {string|undefined} 
20149 		 */
20150 		this.streetAddress = freeformAddress.streetAddress;
20151 		/**
20152 		 * The locality of this address (usually a city or town).
20153 		 * @expose
20154 		 * @type {string|undefined} 
20155 		 */
20156 		this.locality = freeformAddress.locality;
20157 		/**
20158 		 * The region (province, canton, prefecture, state, etc.) where the address is located.
20159 		 * @expose
20160 		 * @type {string|undefined} 
20161 		 */
20162 		this.region = freeformAddress.region;
20163 		/**
20164 		 * Country-specific code for expediting mail. In the US, this is the zip code.
20165 		 * @expose
20166 		 * @type {string|undefined} 
20167 		 */
20168 		this.postalCode = freeformAddress.postalCode;
20169 		/**
20170 		 * Optional city-specific code for a particular post office, used to expidite
20171 		 * delivery.
20172 		 * @expose
20173 		 * @type {string|undefined} 
20174 		 */
20175 		this.postOffice = freeformAddress.postOffice;
20176 		/**
20177 		 * The country of the address.
20178 		 * @expose
20179 		 * @type {string|undefined}
20180 		 */
20181 		this.country = freeformAddress.country;
20182 		if (freeformAddress.countryCode) {
20183 			/**
20184 			 * The 2 or 3 letter ISO 3166 region code for the destination country in this address.
20185 			 * @expose
20186 			 * @type {string} 
20187 			 * 
20188 			 */
20189 			this.countryCode = freeformAddress.countryCode;
20190 		}
20191 		if (freeformAddress.format) {
20192 			/**
20193 			 * private
20194 			 * @type {string}
20195 			 */
20196 			this.format = freeformAddress.format;
20197 		}
20198 		return this;
20199 	}
20200 
20201 	address = freeformAddress.replace(/[ \t\r]+/g, " ").trim();
20202 	address = address.replace(/[\s\n]+$/, "");
20203 	address = address.replace(/^[\s\n]+/, "");
20204 	//console.log("\n\n-------------\nAddress is '" + address + "'");
20205 	
20206 	this.lines = address.split(/[,,\n]/g);
20207 	this.removeEmptyLines(this.lines);
20208 	
20209 	ilib.Address.shared = ilib.Address.shared || {}; 
20210 	if (typeof(ilib.Address.ctry) === 'undefined') {
20211 		ilib.Address.ctry = {}; // make sure not to conflict with the address info
20212 	}
20213 	ilib.CType.isAscii._init(this.sync, this.loadParams, /** @type {function(*)|undefined} */ ilib.bind(this, function() {
20214 		ilib.CType.isIdeo._init(this.sync, this.loadParams, /** @type {function(*)|undefined} */ ilib.bind(this, function() {
20215 			ilib.CType.isDigit._init(this.sync, this.loadParams, /** @type {function(*)|undefined} */ ilib.bind(this, function() {
20216 				if (typeof(ilib.data.nativecountries) === 'undefined') {
20217 					ilib.loadData({
20218 						name: "nativecountries.json", // countries in their own language 
20219 						locale: "-", // only need to load the root file 
20220 						sync: this.sync, 
20221 						loadParams: this.loadParams, 
20222 						callback: /** @type function(Object=):undefined */ ilib.bind(this, /** @type function() */ function(nativecountries) {
20223 							ilib.data.nativecountries = nativecountries;
20224 							this._loadCountries(options && options.onLoad);
20225 						})
20226 					});
20227 				} else {
20228 					this._loadCountries(options && options.onLoad);
20229 				}
20230 			}));
20231 		}));
20232 	}));
20233 };
20234 
20235 /** @protected */
20236 ilib.Address.prototype = {
20237 	/**
20238 	 * @private
20239 	 */
20240 	_loadCountries: function(onLoad) {
20241 		if (typeof(ilib.data.countries) === 'undefined') {
20242 			ilib.loadData({
20243 				name: "countries.json", // countries in English
20244 				locale: "-", // only need to load the root file
20245 				sync: this.sync, 
20246 				loadParams: this.loadParams, 
20247 				callback: /** @type function(Object=):undefined */ ilib.bind(this, /** @type function() */ function(countries) {
20248 					ilib.data.countries = countries;
20249 					this._loadCtrynames(onLoad);
20250 				})
20251 			});
20252 		} else {
20253 			this._loadCtrynames(onLoad);
20254 		}
20255 	},
20256 
20257 	/**
20258 	 * @private
20259 	 */
20260 	_loadCtrynames: function(onLoad) {
20261 		ilib.loadData({
20262 			name: "ctrynames.json", 
20263 			object: ilib.Address.ctry, 
20264 			locale: this.locale, 
20265 			sync: this.sync, 
20266 			loadParams: this.loadParams, 
20267 			callback: /** @type function(Object=):undefined */ ilib.bind(this, /** @type function() */ function(ctrynames) {
20268 				this._determineDest(ctrynames, onLoad);
20269 			})
20270 		});
20271 	},
20272 	
20273 	/**
20274 	 * @private
20275 	 * @param {Object?} ctrynames
20276 	 */
20277 	_findDest: function (ctrynames) {
20278 		var match;
20279 		
20280 		for (var countryName in ctrynames) {
20281 			if (countryName && countryName !== "generated") {
20282 				// find the longest match in the current table
20283 				// ctrynames contains the country names mapped to region code
20284 				// for efficiency, only test for things longer than the current match
20285 				if (!match || match.text.length < countryName.length) {
20286 					var temp = this._findCountry(countryName);
20287 					if (temp) {
20288 						match = temp;
20289 						this.country = match.text;
20290 						this.countryCode = ctrynames[countryName];
20291 					}
20292 				}
20293 			}
20294 		}
20295 		return match;
20296 	},
20297 	
20298 	/**
20299 	 * @private
20300 	 * @param {Object?} localizedCountries
20301 	 * @param {function(ilib.Address):undefined} callback
20302 	 */
20303 	_determineDest: function (localizedCountries, callback) {
20304 		var match;
20305 		
20306 		/*
20307 		 * First, find the name of the destination country, as that determines how to parse
20308 		 * the rest of the address. For any address, there are three possible ways 
20309 		 * that the name of the country could be written:
20310 		 * 1. In the current language
20311 		 * 2. In its own native language
20312 		 * 3. In English
20313 		 * We'll try all three.
20314 		 */
20315 		var tables = [];
20316 		if (localizedCountries) {
20317 			tables.push(localizedCountries);
20318 		}
20319 		tables.push(ilib.data.nativecountries);
20320 		tables.push(ilib.data.countries);
20321 		
20322 		for (var i = 0; i < tables.length; i++) {
20323 			match = this._findDest(tables[i]);
20324 			
20325 			if (match) {
20326 				this.lines[match.line] = this.lines[match.line].substring(0, match.start) + this.lines[match.line].substring(match.start + match.text.length);
20327 
20328 				this._init(callback);
20329 				return;
20330 			}
20331 		}
20332 		
20333 		// no country, so try parsing it as if we were in the same country
20334 		this.country = undefined;
20335 		this.countryCode = this.locale.getRegion();
20336 		this._init(callback);
20337 	},
20338 
20339 	/**
20340 	 * @private
20341 	 * @param {function(ilib.Address):undefined} callback
20342 	 */
20343 	_init: function(callback) {
20344 		ilib.loadData({
20345 			object: ilib.Address, 
20346 			locale: new ilib.Locale(this.countryCode), 
20347 			name: "address.json", 
20348 			sync: this.sync, 
20349 			loadParams: this.loadParams,
20350 			callback: /** @type function(Object=):undefined */ ilib.bind(this, function(info) {
20351 				if (!info || ilib.isEmpty(info)) {
20352 					// load the "unknown" locale instead
20353 					ilib.loadData({
20354 						object: ilib.Address, 
20355 						locale: new ilib.Locale("XX"), 
20356 						name: "address.json", 
20357 						sync: this.sync, 
20358 						loadParams: this.loadParams,
20359 						callback: /** @type function(Object=):undefined */ ilib.bind(this, function(info) {
20360 							this.info = info;
20361 							this._parseAddress();
20362 							if (typeof(callback) === 'function') {
20363 								callback(this);
20364 							}	
20365 						})
20366 					});
20367 				} else {
20368 					this.info = info;
20369 					this._parseAddress();
20370 					if (typeof(callback) === 'function') {
20371 						callback(this);
20372 					}
20373 				}
20374 			})
20375 		});
20376 	},
20377 
20378 	/**
20379 	 * @private
20380 	 */
20381 	_parseAddress: function() {
20382 		// clean it up first
20383 		var i, 
20384 			asianChars = 0, 
20385 			latinChars = 0,
20386 			startAt,
20387 			infoFields,
20388 			field,
20389 			pattern,
20390 			matchFunction,
20391 			match,
20392 			fieldNumber;
20393 		
20394 		// for locales that support both latin and asian character addresses, 
20395 		// decide if we are parsing an asian or latin script address
20396 		if (this.info && this.info.multiformat) {
20397 			for (var j = 0; j < this.lines.length; j++) {
20398 				var line = new ilib.String(this.lines[j]);
20399 				var it = line.charIterator();
20400 				while (it.hasNext()) {
20401 					var c = it.next();
20402 					if (ilib.CType.isIdeo(c) || ilib.CType.withinRange(c, "Hangul")) {
20403 						asianChars++;
20404 					} else if (ilib.CType.isAscii(c) && !ilib.CType.isDigit(c)) {
20405 						latinChars++;
20406 					}
20407 				}
20408 			}
20409 			
20410 			this.format = (asianChars >= latinChars) ? "asian" : "latin";
20411 			startAt = this.info.startAt[this.format];
20412 			infoFields = this.info.fields[this.format];
20413 			// //console.log("multiformat locale: format is now " + this.format);
20414 		} else {
20415 			startAt = (this.info && this.info.startAt) || "end";
20416 			infoFields = this.info.fields;
20417 		}
20418 		this.compare = (startAt === "end") ? this.endsWith : this.startsWith;
20419 		
20420 		//console.log("this.lines is: " + JSON.stringify(this.lines));
20421 		
20422 		for (i = 0; i < infoFields.length && this.lines.length > 0; i++) {
20423 			/** @type {{name:string, line:string, pattern:(string|Array.<string>), matchGroup:number}} */
20424 			field = infoFields[i];
20425 			this.removeEmptyLines(this.lines);
20426 			//console.log("Searching for field " + field.name);
20427 			if (field.pattern) {
20428 				if (typeof(field.pattern) === 'string') {
20429 					pattern = new RegExp(field.pattern, "img");
20430 					matchFunction = this.matchRegExp;
20431 				} else {
20432 					pattern = field.pattern;
20433 					matchFunction = this.matchPattern;
20434 				}
20435 					
20436 				switch (field.line) {
20437 				case 'startAtFirst':
20438 					for (fieldNumber = 0; fieldNumber < this.lines.length; fieldNumber++) {
20439 						match = matchFunction(this, this.lines[fieldNumber], pattern, field.matchGroup, startAt);
20440 						if (match) {
20441 							break;
20442 						}
20443 					}
20444 					break;
20445 				case 'startAtLast':
20446 					for (fieldNumber = this.lines.length-1; fieldNumber >= 0; fieldNumber--) {
20447 						match = matchFunction(this, this.lines[fieldNumber], pattern, field.matchGroup, startAt);
20448 						if (match) {
20449 							break;
20450 						}
20451 					}
20452 					break;
20453 				case 'first':
20454 					fieldNumber = 0;
20455 					match = matchFunction(this, this.lines[fieldNumber], pattern, field.matchGroup, startAt);
20456 					break;
20457 				case 'last':
20458 				default:
20459 					fieldNumber = this.lines.length - 1;
20460 					match = matchFunction(this, this.lines[fieldNumber], pattern, field.matchGroup, startAt);
20461 					break;
20462 				}
20463 				if (match) {
20464 					// //console.log("found match for " + field.name + ": " + JSON.stringify(match));
20465 					// //console.log("remaining line is " + match.line);
20466 					this.lines[fieldNumber] = match.line;
20467 					this[field.name] = match.match;
20468 				}
20469 			} else {
20470 				// if nothing is given, default to taking the whole field
20471 				this[field.name] = this.lines.splice(fieldNumber,1)[0].trim();
20472 				//console.log("typeof(this[field.name]) is " + typeof(this[field.name]) + " and value is " + JSON.stringify(this[field.name]));
20473 			}
20474 		}
20475 			
20476 		// all the left overs go in the street address field
20477 		this.removeEmptyLines(this.lines);
20478 		if (this.lines.length > 0) {
20479 			//console.log("this.lines is " + JSON.stringify(this.lines) + " and splicing to get streetAddress");
20480 			// Korea uses spaces between words, despite being an "asian" locale
20481 			var joinString = (this.info.joinString && this.info.joinString[this.format]) || ((this.format && this.format === "asian") ? "" : ", ");
20482 			this.streetAddress = this.lines.join(joinString).trim();
20483 		}
20484 		
20485 		this.lines = undefined;
20486 		//console.log("final result is " + JSON.stringify(this));
20487 	},
20488 	
20489 	/**
20490 	 * @protected
20491 	 * Find the named country either at the end or the beginning of the address.
20492 	 */
20493 	_findCountry: function(name) {
20494 		var start = -1, match, line = 0;
20495 		
20496 		if (this.lines.length > 0) {
20497 			start = this.startsWith(this.lines[line], name);
20498 			if (start === -1) {
20499 				line = this.lines.length-1;
20500 				start = this.endsWith(this.lines[line], name);
20501 			}
20502 			if (start !== -1) {
20503 				match = {
20504 					text: this.lines[line].substring(start, start + name.length),
20505 					line: line,
20506 					start: start
20507 				};
20508 			}
20509 		}
20510 		
20511 		return match;
20512 	},
20513 	
20514 	endsWith: function (subject, query) {
20515 		var start = subject.length-query.length,
20516 			i,
20517 			pat;
20518 		//console.log("endsWith: checking " + query + " against " + subject);
20519 		for (i = 0; i < query.length; i++) {
20520 			// TODO: use case mapper instead of toLowerCase()
20521 			if (subject.charAt(start+i).toLowerCase() !== query.charAt(i).toLowerCase()) {
20522 				return -1;
20523 			}
20524 		}
20525 		if (start > 0) {
20526 			pat = /\s/;
20527 			if (!pat.test(subject.charAt(start-1))) {
20528 				// make sure if we are not at the beginning of the string, that the match is 
20529 				// not the end of some other word
20530 				return -1;
20531 			}
20532 		}
20533 		return start;
20534 	},
20535 	
20536 	startsWith: function (subject, query) {
20537 		var i;
20538 		// //console.log("startsWith: checking " + query + " against " + subject);
20539 		for (i = 0; i < query.length; i++) {
20540 			// TODO: use case mapper instead of toLowerCase()
20541 			if (subject.charAt(i).toLowerCase() !== query.charAt(i).toLowerCase()) {
20542 				return -1;
20543 			}
20544 		}
20545 		return 0;
20546 	},
20547 	
20548 	removeEmptyLines: function (arr) {
20549 		var i = 0;
20550 		
20551 		while (i < arr.length) {
20552 			if (arr[i]) {
20553 				arr[i] = arr[i].trim();
20554 				if (arr[i].length === 0) {
20555 					arr.splice(i,1);
20556 				} else {
20557 					i++;
20558 				}
20559 			} else {
20560 				arr.splice(i,1);
20561 			}
20562 		}
20563 	},
20564 	
20565 	matchRegExp: function(address, line, expression, matchGroup, startAt) {
20566 		var lastMatch,
20567 			match,
20568 			ret = {},
20569 			last;
20570 		
20571 		//console.log("searching for regexp " + expression.source + " in line " + line);
20572 		
20573 		match = expression.exec(line);
20574 		if (startAt === 'end') {
20575 			while (match !== null && match.length > 0) {
20576 				//console.log("found matches " + JSON.stringify(match));
20577 				lastMatch = match;
20578 				match = expression.exec(line);
20579 			}
20580 			match = lastMatch;
20581 		}
20582 		
20583 		if (match && match !== null) {
20584 			//console.log("found matches " + JSON.stringify(match));
20585 			matchGroup = matchGroup || 0;
20586 			if (match[matchGroup] !== undefined) {
20587 				ret.match = match[matchGroup].trim();
20588 				ret.match = ret.match.replace(/^\-|\-+$/, '');
20589 				ret.match = ret.match.replace(/\s+$/, '');
20590 				last = (startAt === 'end') ? line.lastIndexOf(match[matchGroup]) : line.indexOf(match[matchGroup]); 
20591 				//console.log("last is " + last);
20592 				ret.line = line.slice(0,last);
20593 				if (address.format !== "asian") {
20594 					ret.line += " ";
20595 				}
20596 				ret.line += line.slice(last+match[matchGroup].length);
20597 				ret.line = ret.line.trim();
20598 				//console.log("found match " + ret.match + " from matchgroup " + matchGroup + " and rest of line is " + ret.line);
20599 				return ret;
20600 			}
20601 		//} else {
20602 			//console.log("no match");
20603 		}
20604 		
20605 		return undefined;
20606 	},
20607 	
20608 	matchPattern: function(address, line, pattern, matchGroup) {
20609 		var start,
20610 			j,
20611 			ret = {};
20612 		
20613 		//console.log("searching in line " + line);
20614 		
20615 		// search an array of possible fixed strings
20616 		//console.log("Using fixed set of strings.");
20617 		for (j = 0; j < pattern.length; j++) {
20618 			start = address.compare(line, pattern[j]); 
20619 			if (start !== -1) {
20620                             ret.match = line.substring(start, start+pattern[j].length);
20621                             if (start !== 0) {
20622                                 ret.line = line.substring(0,start).trim();
20623                             } else {
20624                                 ret.line = line.substring(pattern[j].length).trim();
20625                             }
20626 				//console.log("found match " + ret.match + " and rest of line is " + ret.line);
20627                             return ret;
20628 			}
20629 		}
20630 		
20631 		return undefined;
20632 	}
20633 };
20634 
20635 /*
20636  * addressfmt.js - Format an address
20637  * 
20638  * Copyright © 2013-2014, JEDLSoft
20639  *
20640  * Licensed under the Apache License, Version 2.0 (the "License");
20641  * you may not use this file except in compliance with the License.
20642  * You may obtain a copy of the License at
20643  *
20644  *     http://www.apache.org/licenses/LICENSE-2.0
20645  *
20646  * Unless required by applicable law or agreed to in writing, software
20647  * distributed under the License is distributed on an "AS IS" BASIS,
20648  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20649  *
20650  * See the License for the specific language governing permissions and
20651  * limitations under the License.
20652  */
20653 
20654 /* !depends 
20655 ilibglobal.js 
20656 locale.js
20657 addressprs.js
20658 */
20659 
20660 // !data address
20661 
20662 /**
20663  * @class
20664  * Create a new formatter object to format physical addresses in a particular way.
20665  *
20666  * The options object may contain the following properties, both of which are optional:
20667  *
20668  * <ul>
20669  * <li><i>locale</i> - the locale to use to format this address. If not specified, it uses the default locale
20670  * 
20671  * <li><i>style</i> - the style of this address. The default style for each country usually includes all valid 
20672  * fields for that country.
20673  * 
20674  * <li><i>onLoad</i> - a callback function to call when the address info for the
20675  * locale is fully loaded and the address has been parsed. When the onLoad 
20676  * option is given, the address formatter object 
20677  * will attempt to load any missing locale data using the ilib loader callback.
20678  * When the constructor is done (even if the data is already preassembled), the 
20679  * onLoad function is called with the current instance as a parameter, so this
20680  * callback can be used with preassembled or dynamic loading or a mix of the two. 
20681  * 
20682  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
20683  * asynchronously. If this option is given as "false", then the "onLoad"
20684  * callback must be given, as the instance returned from this constructor will
20685  * not be usable for a while. 
20686  *
20687  * <li><i>loadParams</i> - an object containing parameters to pass to the 
20688  * loader callback function when locale data is missing. The parameters are not
20689  * interpretted or modified in any way. They are simply passed along. The object 
20690  * may contain any property/value pairs as long as the calling code is in
20691  * agreement with the loader callback function as to what those parameters mean.
20692  * </ul>
20693  * 
20694  * Depends directive: !depends addressfmt.js
20695  * 
20696  * @constructor
20697  * @param {Object} options options that configure how this formatter should work
20698  * Returns a formatter instance that can format multiple addresses.
20699  */
20700 ilib.AddressFmt = function(options) {
20701 	this.sync = true;
20702 	this.styleName = 'default';
20703 	this.loadParams = {};
20704 	this.locale = new ilib.Locale();
20705 	
20706 	if (options) {
20707 		if (options.locale) {
20708 			this.locale = (typeof(options.locale) === 'string') ? new ilib.Locale(options.locale) : options.locale;
20709 		}
20710 		
20711 		if (typeof(options.sync) !== 'undefined') {
20712 			this.sync = (options.sync == true);
20713 		}
20714 		
20715 		if (options.style) {
20716 			this.styleName = options.style;
20717 		}
20718 		
20719 		if (options.loadParams) {
20720 			this.loadParams = options.loadParams;
20721 		}
20722 	}
20723 	
20724 	// console.log("Creating formatter for region: " + this.locale.region);
20725 	ilib.loadData({
20726 		name: "address.json",
20727 		object: ilib.Address, 
20728 		locale: this.locale,
20729 		sync: this.sync, 
20730 		loadParams: this.loadParams, 
20731 		callback: /** @type function(Object?):undefined */ ilib.bind(this, function(info) {
20732 			if (!info || ilib.isEmpty(info)) {
20733 				// load the "unknown" locale instead
20734 				ilib.loadData({
20735 					name: "address.json",
20736 					object: ilib.Address, 
20737 					locale: new ilib.Locale("XX"),
20738 					sync: this.sync, 
20739 					loadParams: this.loadParams, 
20740 					callback: /** @type function(Object?):undefined */ ilib.bind(this, function(info) {
20741 						this.info = info;
20742 						this._init();
20743 						if (options && typeof(options.onLoad) === 'function') {
20744 							options.onLoad(this);
20745 						}
20746 					})
20747 				});
20748 			} else {
20749 				this.info = info;
20750 				this._init();
20751 				if (options && typeof(options.onLoad) === 'function') {
20752 					options.onLoad(this);
20753 				}
20754 			}
20755 		})
20756 	});
20757 };
20758 
20759 /**
20760  * @private
20761  */
20762 ilib.AddressFmt.prototype._init = function () {
20763 	this.style = this.info && this.info.formats && this.info.formats[this.styleName];
20764 	
20765 	// use generic default -- should not happen, but just in case...
20766 	this.style = this.style || (this.info && this.info.formats["default"]) || "{streetAddress}\n{locality} {region} {postalCode}\n{country}";
20767 };
20768 
20769 /**
20770  * This function formats a physical address (ilib.Address instance) for display. 
20771  * Whitespace is trimmed from the beginning and end of final resulting string, and 
20772  * multiple consecutive whitespace characters in the middle of the string are 
20773  * compressed down to 1 space character.
20774  * 
20775  * If the Address instance is for a locale that is different than the locale for this
20776  * formatter, then a hybrid address is produced. The country name is located in the
20777  * correct spot for the current formatter's locale, but the rest of the fields are
20778  * formatted according to the default style of the locale of the actual address.
20779  * 
20780  * Example: a mailing address in China, but formatted for the US might produce the words
20781  * "People's Republic of China" in English at the last line of the address, and the 
20782  * Chinese-style address will appear in the first line of the address. In the US, the
20783  * country is on the last line, but in China the country is usually on the first line.
20784  *
20785  * @param {ilib.Address} address Address to format
20786  * @eturns {string} Returns a string containing the formatted address
20787  */
20788 ilib.AddressFmt.prototype.format = function (address) {
20789 	var ret, template, other, format;
20790 	
20791 	if (!address) {
20792 		return "";
20793 	}
20794 	// console.log("formatting address: " + JSON.stringify(address));
20795 	if (address.countryCode && 
20796 			address.countryCode !== this.locale.region && 
20797 			ilib.Locale._isRegionCode(this.locale.region) && 
20798 			this.locale.region !== "XX") {
20799 		// we are formatting an address that is sent from this country to another country,
20800 		// so only the country should be in this locale, and the rest should be in the other
20801 		// locale
20802 		// console.log("formatting for another locale. Loading in its settings: " + address.countryCode);
20803 		other = new ilib.AddressFmt({
20804 			locale: new ilib.Locale(address.countryCode), 
20805 			style: this.styleName
20806 		});
20807 		return other.format(address);
20808 	}
20809 	
20810 	if (typeof(this.style) === 'object') {
20811 		format = this.style[address.format || "latin"];
20812 	} else {
20813 		format = this.style;
20814 	}
20815 	
20816 	// console.log("Using format: " + format);
20817 	// make sure we have a blank string for any missing parts so that
20818 	// those template parts get blanked out
20819 	var params = {
20820 		country: address.country || "",
20821 		region: address.region || "",
20822 		locality: address.locality || "",
20823 		streetAddress: address.streetAddress || "",
20824 		postalCode: address.postalCode || "",
20825 		postOffice: address.postOffice || ""
20826 	};
20827 	template = new ilib.String(format);
20828 	ret = template.format(params);
20829 	ret = ret.replace(/[ \t]+/g, ' ');
20830 	ret = ret.replace("\n ", "\n");
20831 	ret = ret.replace(" \n", "\n");
20832 	return ret.replace(/\n+/g, '\n').trim();
20833 };
20834 
20835 /*
20836  * glyphstring.js - ilib string subclass that allows you to access 
20837  * whole glyphs at a time
20838  * 
20839  * Copyright © 2014, JEDLSoft
20840  *
20841  * Licensed under the Apache License, Version 2.0 (the "License");
20842  * you may not use this file except in compliance with the License.
20843  * You may obtain a copy of the License at
20844  *
20845  *     http://www.apache.org/licenses/LICENSE-2.0
20846  *
20847  * Unless required by applicable law or agreed to in writing, software
20848  * distributed under the License is distributed on an "AS IS" BASIS,
20849  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20850  *
20851  * See the License for the specific language governing permissions and
20852  * limitations under the License.
20853  */
20854 
20855 // !depends strings.js ctype.js
20856 // !data norm ctype_m
20857 
20858 /**
20859  * @class
20860  * Create a new glyph string instance. This string inherits from 
20861  * the ilib.String class, and adds methods that allow you to access
20862  * whole glyphs at a time. <p>
20863  * 
20864  * In Unicode, various accented characters can be created by using
20865  * a base character and one or more combining characters following
20866  * it. These appear on the screen to the user as a single glyph.
20867  * For example, the Latin character "a" (U+0061) followed by the
20868  * combining diaresis character "¨" (U+0308) combine together to
20869  * form the "a with diaresis" glyph "ä", which looks like a single
20870  * character on the screen.<p>
20871  * 
20872  * The big problem with combining characters for web developers is
20873  * that many CSS engines do not ellipsize text between glyphs. They
20874  * only deal with single Unicode characters. So if a particular space 
20875  * only allows for 4 characters, the CSS engine will truncate a
20876  * string at 4 Unicode characters and then add the ellipsis (...)
20877  * character. What if the fourth Unicode character is the "a" and
20878  * the fifth one is the diaresis? Then a string like "xxxäxxx" that
20879  * is ellipsized at 4 characters will appear as "xxxa..." on the 
20880  * screen instead of "xxxä...".<p>
20881  * 
20882  * In the Latin script as it is commonly used, it is not so common
20883  * to form accented characters using combining accents, so the above
20884  * example is mostly for illustrative purposes. It is not unheard of
20885  * however. The situation is much, much worse in scripts such as Thai and 
20886  * Devanagari that normally make very heavy use of combining characters.
20887  * These scripts do so because Unicode does not include pre-composed 
20888  * versions of the accented characters like it does for Latin, so 
20889  * combining accents are the only way to create these accented and 
20890  * combined versions of the characters.<p>
20891  * 
20892  * The solution to thise problem is not to use the the CSS property 
20893  * "text-overflow: ellipsis" in your web site, ever. Instead, use
20894  * a glyph string to truncate text between glyphs instead of between
20895  * characters.<p>
20896  * 
20897  * Glyph strings are also useful for truncation, hyphenation, and 
20898  * line wrapping, as all of these should be done between glyphs instead
20899  * of between characters.<p>
20900  * 
20901  * The options parameter is optional, and may contain any combination
20902  * of the following properties:<p>
20903  * 
20904  * <ul>
20905  * <li><i>onLoad</i> - a callback function to call when the locale data are
20906  * fully loaded. When the onLoad option is given, this object will attempt to
20907  * load any missing locale data using the ilib loader callback.
20908  * When the constructor is done (even if the data is already preassembled), the 
20909  * onLoad function is called with the current instance as a parameter, so this
20910  * callback can be used with preassembled or dynamic loading or a mix of the two.
20911  * 
20912  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
20913  * asynchronously. If this option is given as "false", then the "onLoad"
20914  * callback must be given, as the instance returned from this constructor will
20915  * not be usable for a while.
20916  *  
20917  * <li><i>loadParams</i> - an object containing parameters to pass to the 
20918  * loader callback function when locale data is missing. The parameters are not
20919  * interpretted or modified in any way. They are simply passed along. The object 
20920  * may contain any property/value pairs as long as the calling code is in
20921  * agreement with the loader callback function as to what those parameters mean.
20922  * </ul>
20923  * 
20924  * 
20925  * Depends directive: !depends glyphstring.js
20926  * 
20927  * @constructor
20928  * @param {string|ilib.String=} str initialize this instance with this string 
20929  * @param {Object=} options options governing the way this instance works
20930  */
20931 ilib.GlyphString = function (str, options) {
20932 	ilib.String.call(this, str);
20933 	
20934 	var sync = true;
20935 	var loadParams = {};
20936 	if (options) {
20937 		if (typeof(options.sync) === 'boolean') {
20938 			sync = options.sync;
20939 		}
20940 		if (options.loadParams) {
20941 			loadParams = options.loadParams;
20942 		}
20943 	}
20944 	
20945 	ilib.CType._load("ctype_m", sync, loadParams, function() {
20946 		if (typeof(ilib.data.norm) === 'undefined' || typeof(ilib.data.norm.ccc) === 'undefined') {
20947 			ilib.loadData({
20948 				object: ilib.GlyphString, 
20949 				locale: "-", 
20950 				name: "norm.json",
20951 				nonlocale: true,
20952 				sync: sync, 
20953 				loadParams: loadParams, 
20954 				callback: ilib.bind(this, function (norm) {
20955 					ilib.data.norm = norm;
20956 					if (options && typeof(options.onLoad) === 'function') {
20957 						options.onLoad(this);
20958 					}
20959 				})
20960 			});
20961 		} else {
20962 			if (options && typeof(options.onLoad) === 'function') {
20963 				options.onLoad(this);
20964 			}
20965 		}
20966 	});
20967 };
20968 
20969 ilib.GlyphString.prototype = new ilib.String();
20970 ilib.GlyphString.parent = ilib.String;
20971 ilib.GlyphString.prototype.constructor = ilib.GlyphString;
20972 
20973 //ilib.GlyphString.prototype.iterator = function () {
20974 
20975 //};
20976 
20977 /**
20978  * Return true if the given character is a leading Jamo (Choseong) character.
20979  * 
20980  * @private
20981  * @static
20982  * @param {number} n code point to check
20983  * @return {boolean} true if the character is a leading Jamo character, 
20984  * false otherwise
20985  */
20986 ilib.GlyphString._isJamoL = function (n) {
20987 	return (n >= 0x1100 && n <= 0x1112);
20988 };
20989 
20990 /**
20991  * Return true if the given character is a vowel Jamo (Jungseong) character.
20992  * 
20993  * @private
20994  * @static
20995  * @param {number} n code point to check
20996  * @return {boolean} true if the character is a vowel Jamo character, 
20997  * false otherwise
20998  */
20999 ilib.GlyphString._isJamoV = function (n) {
21000 	return (n >= 0x1161 && n <= 0x1175);
21001 };
21002 
21003 /**
21004  * Return true if the given character is a trailing Jamo (Jongseong) character.
21005  * 
21006  * @private
21007  * @static
21008  * @param {number} n code point to check
21009  * @return {boolean} true if the character is a trailing Jamo character, 
21010  * false otherwise
21011  */
21012 ilib.GlyphString._isJamoT = function (n) {
21013 	return (n >= 0x11A8 && n <= 0x11C2);
21014 };
21015 
21016 /**
21017  * Return true if the given character is a precomposed Hangul character.
21018  * 
21019  * @private
21020  * @static
21021  * @param {number} n code point to check
21022  * @return {boolean} true if the character is a precomposed Hangul character, 
21023  * false otherwise
21024  */
21025 ilib.GlyphString._isHangul = function (n) {
21026 	return (n >= 0xAC00 && n <= 0xD7A3);
21027 };
21028 
21029 /**
21030  * Algorithmically compose an L and a V combining Jamo characters into
21031  * a precomposed Korean syllabic Hangul character. Both should already
21032  * be in the proper ranges for L and V characters. 
21033  * 
21034  * @private
21035  * @static
21036  * @param {number} lead the code point of the lead Jamo character to compose
21037  * @param {number} trail the code point of the trailing Jamo character to compose
21038  * @return {string} the composed Hangul character
21039  */
21040 ilib.GlyphString._composeJamoLV = function (lead, trail) {
21041 	var lindex = lead - 0x1100;
21042 	var vindex = trail - 0x1161;
21043 	return ilib.String.fromCodePoint(0xAC00 + (lindex * 21 + vindex) * 28);
21044 };
21045 
21046 /**
21047  * Algorithmically compose a Hangul LV and a combining Jamo T character 
21048  * into a precomposed Korean syllabic Hangul character. 
21049  * 
21050  * @private
21051  * @static
21052  * @param {number} lead the code point of the lead Hangul character to compose
21053  * @param {number} trail the code point of the trailing Jamo T character to compose
21054  * @return {string} the composed Hangul character
21055  */
21056 ilib.GlyphString._composeJamoLVT = function (lead, trail) {
21057 	return ilib.String.fromCodePoint(lead + (trail - 0x11A7));
21058 };
21059 
21060 /**
21061  * Compose one character out of a leading character and a 
21062  * trailing character. If the characters are Korean Jamo, they
21063  * will be composed algorithmically. If they are any other
21064  * characters, they will be looked up in the nfc tables.
21065  * 
21066  * @private
21067  * @static
21068  * @param {string} lead leading character to compose
21069  * @param {string} trail the trailing character to compose
21070  * @return {string} the fully composed character, or undefined if
21071  * there is no composition for those two characters
21072  */
21073 ilib.GlyphString._compose = function (lead, trail) {
21074 	var first = lead.charCodeAt(0);
21075 	var last = trail.charCodeAt(0);
21076 	if (ilib.GlyphString._isHangul(first) && ilib.GlyphString._isJamoT(last)) {
21077 		return ilib.GlyphString._composeJamoLVT(first, last);
21078 	} else if (ilib.GlyphString._isJamoL(first) && ilib.GlyphString._isJamoV(last)) {
21079 		return ilib.GlyphString._composeJamoLV(first, last);
21080 	}
21081 
21082 	var c = lead + trail;
21083 	return (ilib.data.norm.nfc && ilib.data.norm.nfc[c]);
21084 };
21085 
21086 /**
21087  * Return an iterator that will step through all of the characters
21088  * in the string one at a time, taking care to step through decomposed 
21089  * characters and through surrogate pairs in the UTF-16 encoding 
21090  * as single characters. <p>
21091  * 
21092  * The GlyphString class will return decomposed Unicode characters
21093  * as a single unit that a user might see on the screen as a single
21094  * glyph. If the 
21095  * next character in the iteration is a base character and it is 
21096  * followed by combining characters, the base and all its following 
21097  * combining characters are returned as a single unit.<p>
21098  * 
21099  * The standard Javascript String's charAt() method only
21100  * returns information about a particular 16-bit character in the 
21101  * UTF-16 encoding scheme.
21102  * If the index is pointing to a low- or high-surrogate character,
21103  * it will return that surrogate character rather 
21104  * than the surrogate pair which represents a character 
21105  * in the supplementary planes.<p>
21106  * 
21107  * The iterator instance returned has two methods, hasNext() which
21108  * returns true if the iterator has more characters to iterate through,
21109  * and next() which returns the next character.<p>
21110  * 
21111  * @override
21112  * @return {Object} an iterator 
21113  * that iterates through all the characters in the string
21114  */
21115 ilib.GlyphString.prototype.charIterator = function() {
21116 	var it = ilib.String.prototype.charIterator.call(this);
21117 	
21118 	/**
21119 	 * @constructor
21120 	 */
21121 	function _chiterator (istring) {
21122 		this.index = 0;
21123 		this.spacingCombining = false;
21124 		this.hasNext = function () {
21125 			return !!this.nextChar || it.hasNext();
21126 		};
21127 		this.next = function () {
21128 			var ch = this.nextChar || it.next(),
21129 				prevCcc = ilib.data.norm.ccc[ch],
21130 				nextCcc,
21131 				composed = ch;
21132 			
21133 			this.nextChar = undefined;
21134 			this.spacingCombining = false;
21135 			
21136 			if (ilib.data.norm.ccc && 
21137 					(typeof(ilib.data.norm.ccc[ch]) === 'undefined' || ilib.data.norm.ccc[ch] === 0)) {
21138 				// found a starter... find all the non-starters until the next starter. Must include
21139 				// the next starter because under some odd circumstances, two starters sometimes recompose 
21140 				// together to form another character
21141 				var notdone = true;
21142 				while (it.hasNext() && notdone) {
21143 					this.nextChar = it.next();
21144 					nextCcc = ilib.data.norm.ccc[this.nextChar];
21145 					var codePoint = ilib.String.toCodePoint(this.nextChar, 0);
21146 					// Mn characters are Marks that are non-spacing. These do not take more room than an accent, so they should be 
21147 					// considered part of the on-screen glyph, even if they are non-combining. Mc are marks that are spacing
21148 					// and combining, which means they are part of the glyph, but they cause the glyph to use up more space than
21149 					// just the base character alone.
21150 					var isMn = ilib.CType._inRange(codePoint, "Mn", ilib.data.ctype_m);
21151 					var isMc = ilib.CType._inRange(codePoint, "Mc", ilib.data.ctype_m);
21152 					if (isMn || isMc || (typeof(nextCcc) !== 'undefined' && nextCcc !== 0)) {
21153 						if (isMc) {
21154 							this.spacingCombining = true;
21155 						}
21156 						ch += this.nextChar;
21157 						this.nextChar = undefined;
21158 					} else {
21159 						// found the next starter. See if this can be composed with the previous starter
21160 						var testChar = ilib.GlyphString._compose(composed, this.nextChar);
21161 						if (prevCcc === 0 && typeof(testChar) !== 'undefined') { 
21162 							// not blocked and there is a mapping 
21163 							composed = testChar;
21164 							ch += this.nextChar;
21165 							this.nextChar = undefined;
21166 						} else {
21167 							// finished iterating, leave this.nextChar for the next next() call 
21168 							notdone = false;
21169 						}
21170 					}
21171 					prevCcc = nextCcc;
21172 				}
21173 			}
21174 			return ch;
21175 		};
21176 		// Returns true if the last character returned by the "next" method included
21177 		// spacing combining characters. If it does, then the character was wider than
21178 		// just the base character alone, and the truncation code will not add it.
21179 		this.wasSpacingCombining = function() {
21180 			return this.spacingCombining;
21181 		};
21182 	};
21183 	return new _chiterator(this);
21184 };
21185 
21186 /**
21187  * Truncate the current string at the given number of whole glyphs and return
21188  * the resulting string.
21189  * 
21190  * @param {number} length the number of whole glyphs to keep in the string
21191  * @return {string} a string truncated to the requested number of glyphs
21192  */
21193 ilib.GlyphString.prototype.truncate = function(length) {
21194 	var it = this.charIterator();
21195 	var tr = "";
21196 	for (var i = 0; i < length-1 && it.hasNext(); i++) {
21197 		tr += it.next();
21198 	}
21199 	
21200 	/*
21201 	 * handle the last character separately. If it contains spacing combining
21202 	 * accents, then we must assume that it uses up more horizontal space on
21203 	 * the screen than just the base character by itself, and therefore this
21204 	 * method will not truncate enough characters to fit in the given length.
21205 	 * In this case, we have to chop off not only the combining characters, 
21206 	 * but also the base character as well because the base without the
21207 	 * combining accents is considered a different character.
21208 	 */
21209 	if (i < length && it.hasNext()) {
21210 		var c = it.next();
21211 		if (!it.wasSpacingCombining()) {
21212 			tr += c;
21213 		}
21214 	}
21215 	return tr;
21216 };
21217 
21218 /**
21219  * Truncate the current string at the given number of glyphs and add an ellipsis
21220  * to indicate that is more to the string. The ellipsis forms the last character
21221  * in the string, so the string is actually truncated at length-1 glyphs.
21222  * 
21223  * @param {number} length the number of whole glyphs to keep in the string 
21224  * including the ellipsis
21225  * @return {string} a string truncated to the requested number of glyphs
21226  * with an ellipsis
21227  */
21228 ilib.GlyphString.prototype.ellipsize = function(length) {
21229 	return this.truncate(length > 0 ? length-1 : 0) + "…";
21230 };
21231 
21232 
21233 /*
21234  * normstring.js - ilib normalized string subclass definition
21235  * 
21236  * Copyright © 2013-2014, JEDLSoft
21237  *
21238  * Licensed under the Apache License, Version 2.0 (the "License");
21239  * you may not use this file except in compliance with the License.
21240  * You may obtain a copy of the License at
21241  *
21242  *     http://www.apache.org/licenses/LICENSE-2.0
21243  *
21244  * Unless required by applicable law or agreed to in writing, software
21245  * distributed under the License is distributed on an "AS IS" BASIS,
21246  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21247  *
21248  * See the License for the specific language governing permissions and
21249  * limitations under the License.
21250  */
21251 
21252 // !depends strings.js glyphstring.js
21253 
21254 /**
21255  * @class
21256  * Create a new normalized string instance. This string inherits from 
21257  * the ilib.GlyphString class, and adds the normalize method. It can be
21258  * used anywhere that a normal Javascript string is used. <p>
21259  * 
21260  * Depends directive: !depends normstring.js
21261  * 
21262  * @constructor
21263  * @param {string|ilib.String=} str initialize this instance with this string 
21264  */
21265 ilib.NormString = function (str) {
21266 	ilib.GlyphString.call(this, str);
21267 };
21268 
21269 ilib.NormString.prototype = new ilib.GlyphString();
21270 ilib.NormString.parent = ilib.GlyphString;
21271 ilib.NormString.prototype.constructor = ilib.NormString;
21272 
21273 /**
21274  * Initialize the normalized string routines statically. This
21275  * is intended to be called in a dynamic-load version of ilib
21276  * to load the data need to normalize strings before any instances
21277  * of ilib.NormString are created.<p>
21278  * 
21279  * The options parameter may contain any of the following properties:
21280  * 
21281  * <ul>
21282  * <li><i>form</i> - {string} the normalization form to load
21283  * <li><i>script</i> - {string} load the normalization for this script. If the 
21284  * script is given as "all" then the normalization data for all scripts
21285  * is loaded at the same time
21286  * <li><i>sync</i> - {boolean} whether to load the files synchronously or not
21287  * <li><i>loadParams</i> - {Object} parameters to the loader function
21288  * <li><i>onLoad</i> - {function()} a function to call when the 
21289  * files are done being loaded
21290  * </ul>
21291  * 
21292  * @param {Object} options an object containing properties that govern 
21293  * how to initialize the data
21294  */
21295 ilib.NormString.init = function(options) {
21296 	if (!ilib._load || (typeof(ilib._load) !== 'function' && !(ilib._load instanceof ilib.Loader))) {
21297 		// can't do anything
21298 		return;
21299 	}
21300 	var form = "nfkc";
21301 	var script = "all";
21302 	var sync = true;
21303 	var onLoad = undefined;
21304 	var loadParams = undefined;
21305 	if (options) {
21306 		form = options.form || "nfkc";
21307 		script = options.script || "all";
21308 		sync = typeof(options.sync) !== 'undefined' ? options.sync : true;
21309 		onLoad = typeof(options.onLoad) === 'function' ? options.onLoad : undefined;
21310 		if (options.loadParams) {
21311 			loadParams = options.loadParams;
21312 		}
21313 	}
21314 	var formDependencies = {
21315 		"nfd": ["nfd"],
21316 		"nfc": ["nfd"],
21317 		"nfkd": ["nfkd", "nfd"],
21318 		"nfkc": ["nfkd", "nfd"]
21319 	};
21320 	var files = ["norm.json"];
21321 	var forms = formDependencies[form];
21322 	for (var f in forms) {
21323 		files.push(forms[f] + "/" + script + ".json");
21324 	}
21325 	
21326 	ilib._callLoadData(files, sync, loadParams, function(arr) {
21327 		ilib.data.norm = arr[0];
21328 		for (var i = 1; i < arr.length; i++) {
21329 			if (typeof(arr[i]) !== 'undefined') {
21330 				ilib.data.norm[forms[i-1]] = arr[i];
21331 			}
21332 		}
21333 		
21334 		if (onLoad) {
21335 			onLoad(arr);
21336 		}
21337 	});
21338 };
21339 
21340 /**
21341  * Algorithmically decompose a precomposed Korean syllabic Hangul 
21342  * character into its individual combining Jamo characters. The given 
21343  * character must be in the range of Hangul characters U+AC00 to U+D7A3.
21344  * 
21345  * @private
21346  * @static
21347  * @param {number} cp code point of a Korean Hangul character to decompose
21348  * @return {string} the decomposed string of Jamo characters
21349  */
21350 ilib.NormString._decomposeHangul = function (cp) {
21351 	var sindex = cp - 0xAC00;
21352 	var result = String.fromCharCode(0x1100 + sindex / 588) + 
21353 			String.fromCharCode(0x1161 + (sindex % 588) / 28);
21354 	var t = sindex % 28;
21355 	if (t !== 0) {
21356 		result += String.fromCharCode(0x11A7 + t);
21357 	}
21358 	return result;
21359 };
21360 
21361 /**
21362  * Expand one character according to the given canonical and 
21363  * compatibility mappings.
21364  *
21365  * @private
21366  * @static
21367  * @param {string} ch character to map
21368  * @param {Object} canon the canonical mappings to apply
21369  * @param {Object=} compat the compatibility mappings to apply, or undefined
21370  * if only the canonical mappings are needed
21371  * @return {string} the mapped character
21372  */
21373 ilib.NormString._expand = function (ch, canon, compat) {
21374 	var i, 
21375 		expansion = "",
21376 		n = ch.charCodeAt(0);
21377 	if (ilib.GlyphString._isHangul(n)) {
21378 		expansion = ilib.NormString._decomposeHangul(n);
21379 	} else {
21380 		var result = canon[ch];
21381 		if (!result && compat) {
21382 			result = compat[ch];
21383 		}
21384 		if (result && result !== ch) {
21385 			for (i = 0; i < result.length; i++) {
21386 				expansion += ilib.NormString._expand(result[i], canon, compat);
21387 			}
21388 		} else {
21389 			expansion = ch;
21390 		}
21391 	}
21392 	return expansion;
21393 };
21394 
21395 /**
21396  * Perform the Unicode Normalization Algorithm upon the string and return 
21397  * the resulting new string. The current string is not modified.
21398  * 
21399  * <h2>Forms</h2>
21400  * 
21401  * The forms of possible normalizations are defined by the <a 
21402  * href="http://www.unicode.org/reports/tr15/">Unicode Standard
21403  * Annex (UAX) 15</a>. The form parameter is a string that may have one 
21404  * of the following values:
21405  * 
21406  * <ul>
21407  * <li>nfd - Canonical decomposition. This decomposes characters into
21408  * their exactly equivalent forms. For example, "ü" would decompose
21409  * into a "u" followed by the combining diaeresis character. 
21410  * <li>nfc - Canonical decomposition followed by canonical composition.
21411  * This decomposes and then recomposes character into their shortest
21412  * exactly equivalent forms by recomposing as many combining characters
21413  * as possible. For example, "ü" followed by a combining 
21414  * macron character would decompose into a "u" followed by the combining 
21415  * macron characters the combining diaeresis character, and then be recomposed into
21416  * the u with macron and diaeresis "ṻ" character. The reason that
21417  * the "nfc" form decomposes and then recomposes is that combining characters
21418  * have a specific order under the Unicode Normalization Algorithm, and
21419  * partly composed characters such as the "ü" followed by combining
21420  * marks may change the order of the combining marks when decomposed and
21421  * recomposed.
21422  * <li>nfkd - Compatibility decomposition. This decomposes characters
21423  * into compatible forms that may not be exactly equivalent semantically,
21424  * as well as performing canonical decomposition as well.
21425  * For example, the "œ" ligature character decomposes to the two
21426  * characters "oe" because they are compatible even though they are not 
21427  * exactly the same semantically. 
21428  * <li>nfkc - Compatibility decomposition followed by canonical composition.
21429  * This decomposes characters into compatible forms, then recomposes
21430  * characters using the canonical composition. That is, it breaks down
21431  * characters into the compatible forms, and then recombines all combining
21432  * marks it can with their base characters. For example, the character
21433  * "ǽ" would be normalized to "aé" by first decomposing
21434  * the character into "a" followed by "e" followed by the combining acute accent
21435  * combining mark, and then recomposed to an "a" followed by the "e"
21436  * with acute accent.
21437  * </ul>
21438  * 
21439  * <h2>Operation</h2>
21440  * 
21441  * Two strings a and b can be said to be canonically equivalent if 
21442  * normalize(a) = normalize(b)
21443  * under the nfc normalization form. Two strings can be said to be compatible if
21444  * normalize(a) = normalize(b) under the nfkc normalization form.<p>
21445  * 
21446  * The canonical normalization is often used to see if strings are 
21447  * equivalent to each other, and thus is useful when implementing parsing 
21448  * algorithms or exact matching algorithms. It can also be used to ensure
21449  * that any string output produces a predictable sequence of characters.<p>
21450  * 
21451  * Compatibility normalization 
21452  * does not always preserve the semantic meaning of all the characters, 
21453  * although this is sometimes the behaviour that you are after. It is useful, 
21454  * for example, when doing searches of user-input against text in documents 
21455  * where the matches are supposed to "fuzzy". In this case, both the query
21456  * string and the document string would be mapped to their compatibility 
21457  * normalized forms, and then compared.<p>
21458  * 
21459  * Compatibility normalization also does not guarantee round-trip conversion
21460  * to and from legacy character sets as the normalization is "lossy". It is 
21461  * akin to doing a lower- or upper-case conversion on text -- after casing,
21462  * you cannot tell what case each character is in the original string. It is 
21463  * good for matching and searching, but it rarely good for output because some 
21464  * distinctions or meanings in the original text have been lost.<p>
21465  * 
21466  * Note that W3C normalization for HTML also escapes and unescapes
21467  * HTML character entities such as "&uuml;" for u with diaeresis. This
21468  * method does not do such escaping or unescaping. If normalization is required
21469  * for HTML strings with entities, unescaping should be performed on the string 
21470  * prior to calling this method.<p>
21471  * 
21472  * <h2>Data</h2>
21473  * 
21474  * Normalization requires a fair amount of mapping data, much of which you may 
21475  * not need for the characters expected in your texts. It is possible to assemble
21476  * a copy of ilib that saves space by only including normalization data for 
21477  * those scripts that you expect to encounter in your data.<p>
21478  * 
21479  * The normalization data is organized by normalization form and within there
21480  * by script. To include the normalization data for a particular script with
21481  * a particular normalization form, use the directive:
21482  * 
21483  * <pre><code>
21484  * !depends <form>/<script>.js
21485  * </code></pre>
21486  * 
21487  * Where <form> is the normalization form ("nfd", "nfc", "nfkd", or "nfkc"), and
21488  * <script> is the ISO 15924 code for the script you would like to
21489  * support. Example: to load in the NFC data for Cyrillic, you would use:
21490  * 
21491  * <pre><code>
21492  * !depends nfc/Cyrl.js
21493  * </code></pre>
21494  * 
21495  * Note that because certain normalization forms include others in their algorithm, 
21496  * their data also depends on the data for the other forms. For example, if you 
21497  * include the "nfc" data for a script, you will automatically get the "nfd" data 
21498  * for that same script as well because the NFC algorithm does NFD normalization 
21499  * first. Here are the dependencies:<p>
21500  * 
21501  * <ul>
21502  * <li>NFD -> no dependencies
21503  * <li>NFC -> NFD
21504  * <li>NFKD -> NFD
21505  * <li>NFKC -> NFKD, NFD, NFC
21506  * </ul>
21507  * 
21508  * A special value for the script dependency is "all" which will cause the data for 
21509  * all scripts
21510  * to be loaded for that normalization form. This would be useful if you know that
21511  * you are going to normalize a lot of multilingual text or cannot predict which scripts
21512  * will appear in the input. Because the NFKC form depends on all others, you can 
21513  * get all of the data for all forms automatically by depending on "nfkc/all.js".
21514  * Note that the normalization data for practically all script automatically depend
21515  * on data for the Common script (code "Zyyy") which contains all of the characters
21516  * that are commonly used in many different scripts. Examples of characters in the
21517  * Common script are the ASCII punctuation characters, or the ASCII Arabic 
21518  * numerals "0" through "9".<p>
21519  * 
21520  * By default, none of the data for normalization is automatically 
21521  * included in the preassembled iliball.js file. 
21522  * If you would like to normalize strings, you must assemble
21523  * your own copy of ilib and explicitly include the normalization data
21524  * for those scripts as per the instructions above. This normalization method will 
21525  * produce output, even without the normalization data. However, the output will be 
21526  * simply the same thing as its input for all scripts 
21527  * except Korean Hangul and Jamo, which are decomposed and recomposed 
21528  * algorithmically and therefore do not rely on data.<p>
21529  * 
21530  * If characters are encountered for which there are no normalization data, they
21531  * will be passed through to the output string unmodified.
21532  * 
21533  * @param {string} form The normalization form requested
21534  * @return {ilib.String} a new instance of an ilib.String that has been normalized
21535  * according to the requested form. The current instance is not modified.
21536  */
21537 ilib.NormString.prototype.normalize = function (form) {
21538 	var i;
21539 	
21540 	if (typeof(form) !== 'string' || this.str.length === 0) {
21541 		return new ilib.String(this.str);
21542 	}
21543 	
21544 	var nfc = false,
21545 		nfkd = false;
21546 	
21547 	switch (form) {
21548 	default:
21549 		break;
21550 		
21551 	case "nfc":
21552 		nfc = true;
21553 		break;
21554 		
21555 	case "nfkd":
21556 		nfkd = true;
21557 		break;
21558 		
21559 	case "nfkc":
21560 		nfkd = true;
21561 		nfc = true;
21562 		break;
21563 	}
21564 
21565 	// decompose
21566 	var decomp = "";
21567 	
21568 	if (nfkd) {
21569 		var ch, it = ilib.String.prototype.charIterator.call(this);
21570 		while (it.hasNext()) {
21571 			ch = it.next();
21572 			decomp += ilib.NormString._expand(ch, ilib.data.norm.nfd, ilib.data.norm.nfkd);
21573 		}
21574 	} else {
21575 		var ch, it = ilib.String.prototype.charIterator.call(this);
21576 		while (it.hasNext()) {
21577 			ch = it.next();
21578 			decomp += ilib.NormString._expand(ch, ilib.data.norm.nfd);
21579 		}
21580 	}
21581 
21582 	// now put the combining marks in a fixed order by 
21583 	// sorting on the combining class
21584 	function compareByCCC(left, right) {
21585 		return ilib.data.norm.ccc[left] - ilib.data.norm.ccc[right]; 
21586 	}
21587 	
21588 	function ccc(c) {
21589 		return ilib.data.norm.ccc[c] || 0;
21590 	}
21591 		
21592 	var dstr = new ilib.String(decomp);
21593 	var it = dstr.charIterator();
21594 	var cpArray = [];
21595 
21596 	// easier to deal with as an array of chars
21597 	while (it.hasNext()) {
21598 		cpArray.push(it.next());
21599 	}
21600 	
21601 	i = 0;
21602 	while (i < cpArray.length) {
21603 		if (typeof(ilib.data.norm.ccc[cpArray[i]]) !== 'undefined' && ccc(cpArray[i]) !== 0) {
21604 			// found a non-starter... rearrange all the non-starters until the next starter
21605 			var end = i+1;
21606 			while (end < cpArray.length &&
21607 					typeof(ilib.data.norm.ccc[cpArray[end]]) !== 'undefined' && 
21608 					ccc(cpArray[end]) !== 0) {
21609 				end++;
21610 			}
21611 			
21612 			// simple sort of the non-starter chars
21613 			if (end - i > 1) {
21614 				cpArray = cpArray.slice(0,i).concat(cpArray.slice(i, end).sort(compareByCCC), cpArray.slice(end));
21615 			}
21616 		}
21617 		i++;
21618 	}
21619 	
21620 	if (nfc) {
21621 		i = 0;
21622 		while (i < cpArray.length) {
21623 			if (typeof(ilib.data.norm.ccc[cpArray[i]]) === 'undefined' || ilib.data.norm.ccc[cpArray[i]] === 0) {
21624 				// found a starter... find all the non-starters until the next starter. Must include
21625 				// the next starter because under some odd circumstances, two starters sometimes recompose 
21626 				// together to form another character
21627 				var end = i+1;
21628 				var notdone = true;
21629 				while (end < cpArray.length && notdone) {
21630 					if (typeof(ilib.data.norm.ccc[cpArray[end]]) !== 'undefined' && 
21631 						ilib.data.norm.ccc[cpArray[end]] !== 0) {
21632 						if (ccc(cpArray[end-1]) < ccc(cpArray[end])) { 
21633 							// not blocked 
21634 							var testChar = ilib.GlyphString._compose(cpArray[i], cpArray[end]);
21635 							if (typeof(testChar) !== 'undefined') {
21636 								cpArray[i] = testChar;
21637 								
21638 								// delete the combining char
21639 								cpArray.splice(end,1);	
21640 								
21641 								// restart the iteration, just in case there is more to recompose with the new char
21642 								end = i;
21643 							}
21644 						}
21645 						end++;
21646 					} else {
21647 						// found the next starter. See if this can be composed with the previous starter
21648 						var testChar = ilib.GlyphString._compose(cpArray[i], cpArray[end]);
21649 						if (ccc(cpArray[end-1]) === 0 && typeof(testChar) !== 'undefined') { 
21650 							// not blocked and there is a mapping 
21651 							cpArray[i] = testChar;
21652 							
21653 							// delete the combining char
21654 							cpArray.splice(end,1);
21655 							
21656 							// restart the iteration, just in case there is more to recompose with the new char
21657 							end = i+1;
21658 						} else {
21659 							// finished iterating 
21660 							notdone = false;
21661 						}
21662 					}
21663 				}
21664 			}
21665 			i++;
21666 		}
21667 	}
21668 	
21669 	return new ilib.String(cpArray.length > 0 ? cpArray.join("") : "");
21670 };
21671 	
21672 /**
21673  * @override
21674  * Return an iterator that will step through all of the characters
21675  * in the string one at a time, taking care to step through decomposed 
21676  * characters and through surrogate pairs in UTF-16 encoding 
21677  * properly. <p>
21678  * 
21679  * The NormString class will return decomposed Unicode characters
21680  * as a single unit that a user might see on the screen. If the 
21681  * next character in the iteration is a base character and it is 
21682  * followed by combining characters, the base and all its following 
21683  * combining characters are returned as a single unit.<p>
21684  * 
21685  * The standard Javascript String's charAt() method only
21686  * returns information about a particular 16-bit character in the 
21687  * UTF-16 encoding scheme.
21688  * If the index is pointing to a low- or high-surrogate character,
21689  * it will return that surrogate character rather 
21690  * than the surrogate pair which represents a character 
21691  * in the supplementary planes.<p>
21692  * 
21693  * The iterator instance returned has two methods, hasNext() which
21694  * returns true if the iterator has more characters to iterate through,
21695  * and next() which returns the next character.<p>
21696  * 
21697  * @return {Object} an iterator 
21698  * that iterates through all the characters in the string
21699  */
21700 ilib.NormString.prototype.charIterator = function() {
21701 	var it = ilib.String.prototype.charIterator.call(this);
21702 	
21703 	/**
21704 	 * @constructor
21705 	 */
21706 	function _chiterator (istring) {
21707 		/**
21708 		 * @private
21709 		 */
21710 		var ccc = function(c) {
21711 			return ilib.data.norm.ccc[c] || 0;
21712 		};
21713 
21714 		this.index = 0;
21715 		this.hasNext = function () {
21716 			return !!this.nextChar || it.hasNext();
21717 		};
21718 		this.next = function () {
21719 			var ch = this.nextChar || it.next(),
21720 				prevCcc = ccc(ch),
21721 				nextCcc,
21722 				composed = ch;
21723 			
21724 			this.nextChar = undefined;
21725 			
21726 			if (ilib.data.norm.ccc && 
21727 					(typeof(ilib.data.norm.ccc[ch]) === 'undefined' || ccc(ch) === 0)) {
21728 				// found a starter... find all the non-starters until the next starter. Must include
21729 				// the next starter because under some odd circumstances, two starters sometimes recompose 
21730 				// together to form another character
21731 				var notdone = true;
21732 				while (it.hasNext() && notdone) {
21733 					this.nextChar = it.next();
21734 					nextCcc = ccc(this.nextChar);
21735 					if (typeof(ilib.data.norm.ccc[this.nextChar]) !== 'undefined' && nextCcc !== 0) {
21736 						ch += this.nextChar;
21737 						this.nextChar = undefined;
21738 					} else {
21739 						// found the next starter. See if this can be composed with the previous starter
21740 						var testChar = ilib.GlyphString._compose(composed, this.nextChar);
21741 						if (prevCcc === 0 && typeof(testChar) !== 'undefined') { 
21742 							// not blocked and there is a mapping 
21743 							composed = testChar;
21744 							ch += this.nextChar;
21745 							this.nextChar = undefined;
21746 						} else {
21747 							// finished iterating, leave this.nextChar for the next next() call 
21748 							notdone = false;
21749 						}
21750 					}
21751 					prevCcc = nextCcc;
21752 				}
21753 			}
21754 			return ch;
21755 		};
21756 	};
21757 	return new _chiterator(this);
21758 };
21759 
21760 
21761 /*
21762  * collate.js - Collation routines
21763  * 
21764  * Copyright © 2013-2014, JEDLSoft
21765  *
21766  * Licensed under the Apache License, Version 2.0 (the "License");
21767  * you may not use this file except in compliance with the License.
21768  * You may obtain a copy of the License at
21769  *
21770  *     http://www.apache.org/licenses/LICENSE-2.0
21771  *
21772  * Unless required by applicable law or agreed to in writing, software
21773  * distributed under the License is distributed on an "AS IS" BASIS,
21774  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21775  *
21776  * See the License for the specific language governing permissions and
21777  * limitations under the License.
21778  */
21779 
21780 // !depends locale.js ilibglobal.js numprs.js ctype.ispunct.js normstring.js util/math.js
21781 
21782 // !data collation
21783 
21784 /**
21785  * @class
21786  * Represents a buffered source of code points. The input string is first
21787  * normalized so that combining characters come out in a standardized order.
21788  * If the "ignorePunctuation" flag is turned on, then punctuation 
21789  * characters are skipped.
21790  * 
21791  * @constructor
21792  * @private
21793  * @param {ilib.NormString|string} str a string to get code points from
21794  * @param {boolean} ignorePunctuation whether or not to ignore punctuation
21795  * characters
21796  */
21797 ilib.CodePointSource = function(str, ignorePunctuation) {
21798 	this.chars = [];
21799 	// first convert the string to a normalized sequence of characters
21800 	var s = (typeof(str) === "string") ? new ilib.NormString(str) : str;
21801 	this.it = s.charIterator();
21802 	this.ignorePunctuation = typeof(ignorePunctuation) === "boolean" && ignorePunctuation;
21803 };
21804 
21805 /**
21806  * Return the first num code points in the source without advancing the
21807  * source pointer. If there are not enough code points left in the
21808  * string to satisfy the request, this method will return undefined. 
21809  * 
21810  * @param {number} num the number of characters to peek ahead
21811  * @return {string|undefined} a string formed out of up to num code points from
21812  * the start of the string, or undefined if there are not enough character left
21813  * in the source to complete the request
21814  */
21815 ilib.CodePointSource.prototype.peek = function(num) {
21816 	if (num < 1) {
21817 		return undefined;
21818 	}
21819 	if (this.chars.length < num && this.it.hasNext()) {
21820 		for (var i = 0; this.chars.length < 4 && this.it.hasNext(); i++) {
21821 			var c = this.it.next();
21822 			if (c && !this.ignorePunctuation || !ilib.CType.isPunct(c)) {
21823 				this.chars.push(c);
21824 			}
21825 		}
21826 	}
21827 	if (this.chars.length < num) {
21828 		return undefined;
21829 	}
21830 	return this.chars.slice(0, num).join("");
21831 };
21832 /**
21833  * Advance the source pointer by the given number of code points.
21834  * @param {number} num number of code points to advance
21835  */
21836 ilib.CodePointSource.prototype.consume = function(num) {
21837 	if (num > 0) {
21838 		this.peek(num); // for the iterator to go forward if needed
21839 		if (num < this.chars.length) {
21840 			this.chars = this.chars.slice(num);
21841 		} else {
21842 			this.chars = [];
21843 		}
21844 	}
21845 };
21846 
21847 
21848 /**
21849  * @class
21850  * An iterator through a sequence of collation elements. This
21851  * iterator takes a source of code points, converts them into
21852  * collation elements, and allows the caller to get single
21853  * elements at a time.
21854  * 
21855  * @constructor
21856  * @private
21857  * @param {ilib.CodePointSource} source source of code points to 
21858  * convert to collation elements
21859  * @param {Object} map mapping from sequences of code points to
21860  * collation elements
21861  * @param {number} keysize size in bits of the collation elements
21862  */
21863 ilib.ElementIterator = function (source, map, keysize) {
21864 	this.elements = [];
21865 	this.source = source;
21866 	this.map = map;
21867 	this.keysize = keysize;
21868 };
21869 
21870 /**
21871  * @private
21872  */
21873 ilib.ElementIterator.prototype._fillBuffer = function () {
21874 	var str = undefined;
21875 	
21876 	// peek ahead by up to 4 characters, which may combine
21877 	// into 1 or more collation elements
21878 	for (var i = 4; i > 0; i--) {
21879 		str = this.source.peek(i);
21880 		if (str && this.map[str]) {
21881 			this.elements = this.elements.concat(this.map[str]);
21882 			this.source.consume(i);
21883 			return;
21884 		}
21885 	}
21886 	
21887 	if (str) {
21888 		// no mappings for the first code point, so just use its
21889 		// Unicode code point as a proxy for its sort order. Shift
21890 		// it by the key size so that everything unknown sorts
21891 		// after things that have mappings
21892 		this.elements.push(str.charCodeAt(0) << this.keysize);
21893 		this.source.consume(1);
21894 	} else {
21895 		// end of the string
21896 		return undefined;
21897 	}
21898 };
21899 
21900 /**
21901  * Return true if there are more collation elements left to
21902  * iterate through.
21903  * @returns {boolean} true if there are more elements left to
21904  * iterate through, and false otherwise
21905  */
21906 ilib.ElementIterator.prototype.hasNext = function () {
21907 	if (this.elements.length < 1) {
21908 		this._fillBuffer();
21909 	}
21910 	return !!this.elements.length;
21911 };
21912 
21913 /**
21914  * Return the next collation element. If more than one collation 
21915  * element is generated from a sequence of code points 
21916  * (ie. an "expansion"), then this class will buffer the
21917  * other elements and return them on subsequent calls to 
21918  * this method.
21919  * 
21920  * @returns {number|undefined} the next collation element or
21921  * undefined for no more collation elements
21922  */
21923 ilib.ElementIterator.prototype.next = function () {
21924 	if (this.elements.length < 1) {
21925 		this._fillBuffer();
21926 	}
21927 	var ret = this.elements[0];
21928 	this.elements = this.elements.slice(1);
21929 	return ret;
21930 };
21931 
21932 
21933 /**
21934  * @class
21935  * A class that implements a locale-sensitive comparator function 
21936  * for use with sorting function. The comparator function
21937  * assumes that the strings it is comparing contain Unicode characters
21938  * encoded in UTF-16.<p>
21939  * 
21940  * Collations usually depend only on the language, because most collation orders 
21941  * are shared between locales that speak the same language. There are, however, a
21942  * number of instances where a locale collates differently than other locales
21943  * that share the same language. There are also a number of instances where a
21944  * locale collates differently based on the script used. This object can handle
21945  * these cases automatically if a full locale is specified in the options rather
21946  * than just a language code.<p>
21947  * 
21948  * <h2>Options</h2>
21949  * 
21950  * The options parameter can contain any of the following properties:
21951  * 
21952  * <ul>
21953  * <li><i>locale</i> - String|Locale. The locale which the comparator function 
21954  * will collate with. Default: the current iLib locale.
21955  * 
21956  * <li><i>sensitivity</i> - String. Sensitivity or strength of collator. This is one of 
21957  * "primary", "base", "secondary", "accent", "tertiary", "case", "quaternary", or 
21958  * "variant". Default: "primary"
21959  *   <ol>
21960  *   <li>base or primary - Only the primary distinctions between characters are significant.
21961  *   Another way of saying that is that the collator will be case-, accent-, and 
21962  *   variation-insensitive, and only distinguish between the base characters
21963  *   <li>case or secondary - Both the primary and secondary distinctions between characters
21964  *   are significant. That is, the collator will be accent- and variation-insensitive
21965  *   and will distinguish between base characters and character case.
21966  *   <li>accent or tertiary - The primary, secondary, and tertiary distinctions between
21967  *   characters are all significant. That is, the collator will be 
21968  *   variation-insensitive, but accent-, case-, and base-character-sensitive. 
21969  *   <li>variant or quaternary - All distinctions between characters are significant. That is,
21970  *   the algorithm is base character-, case-, accent-, and variation-sensitive.
21971  *   </ol>
21972  *   
21973  * <li><i>upperFirst</i> - boolean. When collating case-sensitively in a script that
21974  * has the concept of case, put upper-case
21975  * characters first, otherwise lower-case will come first. Warning: some browsers do
21976  * not implement this feature or at least do not implement it properly, so if you are 
21977  * using the native collator with this option, you may get different results in different
21978  * browsers. To guarantee the same results, set useNative to false to use the ilib 
21979  * collator implementation. This of course will be somewhat slower, but more 
21980  * predictable. Default: true
21981  * 
21982  * <li><i>reverse</i> - boolean. Return the list sorted in reverse order. When the
21983  * upperFirst option is also set to true, upper-case characters would then come at 
21984  * the end of the list. Default: false.
21985  * 
21986  * <li><i>scriptOrder</i> - string. When collating strings in multiple scripts,
21987  * this property specifies what order those scripts should be sorted. The default
21988  * Unicode Collation Algorithm (UCA) already has a default order for scripts, but
21989  * this can be tailored via this property. The value of this option is a 
21990  * space-separated list of ISO 15924 scripts codes. If a code is specified in this
21991  * property, its default data must be included using the JS assembly tool. If the
21992  * data is not included, the ordering for the script will be ignored. Default:
21993  * the default order defined by the UCA. 
21994  * 
21995  * <li><i>style</i> - The value of the style parameter is dependent on the locale.
21996  * For some locales, there are different styles of collating strings depending
21997  * on what kind of strings are being collated or what the preference of the user 
21998  * is. For example, in German, there is a phonebook order and a dictionary ordering
21999  * that sort the same array of strings slightly differently.
22000  * The static method {@link ilib.Collator#getAvailableStyles} will return a list of styles that ilib
22001  * currently knows about for any given locale. If the value of the style option is 
22002  * not recognized for a locale, it will be ignored. Default style is "standard".<p>
22003  * 
22004  * <li><i>usage</i> - Whether this collator will be used for searching or sorting.
22005  * Valid values are simply the strings "sort" or "search". When used for sorting,
22006  * it is good idea if a collator produces a stable sort. That is, the order of the 
22007  * sorted array of strings should not depend on the order of the strings in the
22008  * input array. As such, when a collator is supposed to act case insensitively, 
22009  * it nonetheless still distinguishes between case after all other criteria
22010  * are satisfied so that strings that are distinguished only by case do not sort
22011  * randomly. For searching, we would like to match two strings that different only 
22012  * by case, so the collator must return equals in that situation instead of 
22013  * further distinguishing by case. Default is "sort".
22014  * 
22015  * <li><i>numeric</i> - Treat the left and right strings as if they started with
22016  * numbers and sort them numerically rather than lexically.
22017  * 
22018  * <li><i>ignorePunctuation</i> - Skip punctuation characters when comparing the
22019  * strings.
22020  *  
22021  * <li>onLoad - a callback function to call when the collator object is fully 
22022  * loaded. When the onLoad option is given, the collator object will attempt to
22023  * load any missing locale data using the ilib loader callback.
22024  * When the constructor is done (even if the data is already preassembled), the 
22025  * onLoad function is called with the current instance as a parameter, so this
22026  * callback can be used with preassembled or dynamic loading or a mix of the two.
22027  * 
22028  * <li>sync - tell whether to load any missing locale data synchronously or 
22029  * asynchronously. If this option is given as "false", then the "onLoad"
22030  * callback must be given, as the instance returned from this constructor will
22031  * not be usable for a while. 
22032  *
22033  * <li><i>loadParams</i> - an object containing parameters to pass to the 
22034  * loader callback function when locale data is missing. The parameters are not
22035  * interpretted or modified in any way. They are simply passed along. The object 
22036  * may contain any property/value pairs as long as the calling code is in
22037  * agreement with the loader callback function as to what those parameters mean.
22038  * 
22039  * <li><i>useNative</i> - when this option is true, use the native Intl object
22040  * provided by the Javascript engine, if it exists, to implement this class. If
22041  * it doesn't exist, or if this parameter is false, then this class uses a pure 
22042  * Javascript implementation, which is slower and uses a lot more memory, but 
22043  * works everywhere that ilib works. Default is "true".
22044  * </ul>
22045  * 
22046  * <h2>Operation</h2>
22047  * 
22048  * The Collator constructor returns a collator object tailored with the above 
22049  * options. The object contains an internal compare() method which compares two 
22050  * strings according to those options. This can be used directly to compare
22051  * two strings, but is not useful for passing to the javascript sort function
22052  * because then it will not have its collation data available. Instead, use the 
22053  * getComparator() method to retrieve a function that is bound to the collator
22054  * object. (You could also bind it yourself using ilib.bind()). The bound function 
22055  * can be used with the standard Javascript array sorting algorithm, or as a 
22056  * comparator with your own sorting algorithm.<p>
22057  * 
22058  * Example using the standard Javascript array sorting call with the bound
22059  * function:<p>
22060  * 
22061  * <code>
22062  * <pre>
22063  * var arr = ["ö", "oe", "ü", "o", "a", "ae", "u", "ß", "ä"];
22064  * var collator = ilib.Collator({locale: 'de-DE', style: "dictionary"});
22065  * arr.sort(collator.getComparator());
22066  * console.log(JSON.stringify(arr));
22067  * </pre>
22068  * </code>
22069  * <p>
22070  * 
22071  * Would give the output:<p>
22072  * 
22073  * <code>
22074  * <pre>
22075  * ["a", "ae", "ä", "o", "oe", "ö", "ß", "u", "ü"]
22076  * </pre>
22077  * </code>
22078  * 
22079  * When sorting an array of Javascript objects according to one of the 
22080  * string properties of the objects, wrap the collator's compare function 
22081  * in your own comparator function that knows the structure of the objects
22082  * being sorted:<p>
22083  * 
22084  * <code>
22085  * <pre>
22086  * var collator = ilib.Collator({locale: 'de-DE'});
22087  * var myComparator = function (collator) {
22088  *   var comparator = collator.getComparator();
22089  *   // left and right are your own objects
22090  *   return function (left, right) {
22091  *   	return comparator(left.x.y.textProperty, right.x.y.textProperty);
22092  *   };
22093  * };
22094  * arr.sort(myComparator(collator));
22095  * </pre>
22096  * </code>
22097  * <p>
22098  * 
22099  * <h2>Sort Keys</h2>
22100  * 
22101  * The collator class also has a method to retrieve the sort key for a
22102  * string. The sort key is an array of values that represent how each  
22103  * character in the string should be collated according to the characteristics
22104  * of the collation algorithm and the given options. Thus, sort keys can be 
22105  * compared directly value-for-value with other sort keys that were generated 
22106  * by the same collator, and the resulting ordering is guaranteed to be the 
22107  * same as if the original strings were compared by the collator.
22108  * Sort keys generated by different collators are not guaranteed to give
22109  * any reasonable results when compared together unless the two collators 
22110  * were constructed with 
22111  * exactly the same options and therefore end up representing the exact same 
22112  * collation sequence.<p>
22113  * 
22114  * A good rule of thumb is that you would use a sort key if you had 10 or more
22115  * items to sort or if your array might be resorted arbitrarily. For example, if your 
22116  * user interface was displaying a table with 100 rows in it, and each row had
22117  * 4 sortable text columns which could be sorted in acending or descending order,
22118  * the recommended practice would be to generate a sort key for each of the 4
22119  * sortable fields in each row and store that in the Javascript representation of the
22120  * table data. Then, when the user clicks on a column header to resort the
22121  * table according to that column, the resorting would be relatively quick 
22122  * because it would only be comparing arrays of values, and not recalculating 
22123  * the collation values for each character in each string for every comparison.<p>
22124  * 
22125  * For tables that are large, it is usually a better idea to do the sorting
22126  * on the server side, especially if the table is the result of a database
22127  * query. In this case, the table is usually a view of the cursor of a large
22128  * results set, and only a few entries are sent to the front end at a time.
22129  * In order to sort the set efficiently, it should be done on the database
22130  * level instead.
22131  * 
22132  * <h2>Data</h2>
22133  * 
22134  * Doing correct collation entails a huge amount of mapping data, much of which is
22135  * not necessary when collating in one language with one script, which is the most
22136  * common case. Thus, ilib implements a number of ways to include the data you
22137  * need or leave out the data you don't need using the JS assembly tool:
22138  * 
22139  * <ol>
22140  * <li>Full multilingual data - if you are sorting multilingual data and need to collate 
22141  * text written in multiple scripts, you can use the directive "!data collation/ducet" to 
22142  * load in the full collation data.  This allows the collator to perform the entire 
22143  * Unicode Collation Algorithm (UCA) based on the Default Unicode Collation Element 
22144  * Table (DUCET). The data is very large, on the order of multiple megabytes, but 
22145  * sometimes it is necessary.
22146  * <li>A few scripts - if you are sorting text written in only a few scripts, you may 
22147  * want to include only the data for those scripts. Each ISO 15924 script code has its
22148  * own data available in a separate file, so you can use the data directive to include
22149  * only the data for the scripts you need. For example, use  
22150  * "!data collation/Latn" to retrieve the collation information for the Latin script.
22151  * Because the "ducet" table mentioned in the previous point is a superset of the 
22152  * tables for all other scripts, you do not need to include explicitly the data for 
22153  * any particular script when using "ducet". That is, you either include "ducet" or 
22154  * you include a specific list of scripts.
22155  * <li>Only one script - if you are sorting text written only in one script, you can
22156  * either include the data directly as in the previous point, or you can rely on the 
22157  * locale to include the correct data for you. In this case, you can use the directive
22158  * "!data collate" to load in the locale's collation data for its most common script.
22159  * </ol>
22160  *   
22161  * With any of the above ways of including the data, the collator will only perform the
22162  * correct language-sensitive sorting for the given locale. All other scripts will be
22163  * sorted in the default manner according to the UCA. For example, if you include the
22164  * "ducet" data and pass in "de-DE" (German for Germany) as the locale spec, then
22165  * only the Latin script (the default script for German) will be sorted according to
22166  * German rules. All other scripts in the DUCET, such as Japanese or Arabic, will use 
22167  * the default UCA collation rules.<p>
22168  * 
22169  * If this collator encounters a character for which it has no collation data, it will
22170  * sort those characters by pure Unicode value after all characters for which it does have
22171  * collation data. For example, if you only loaded in the German collation data (ie. the
22172  * data for the Latin script tailored to German) to sort a list of person names, but that
22173  * list happens to include the names of a few Japanese people written in Japanese 
22174  * characters, the Japanese names will sort at the end of the list after all German names,
22175  * and will sort according to the Unicode values of the characters.
22176  * 
22177  * @constructor
22178  * @param {Object} options options governing how the resulting comparator 
22179  * function will operate
22180  */
22181 ilib.Collator = function(options) {
22182 	var sync = true,
22183 		loadParams = undefined,
22184 		useNative = true;
22185 
22186 	// defaults
22187 	/** 
22188 	 * @private
22189 	 * @type {ilib.Locale} 
22190 	 */
22191 	this.locale = new ilib.Locale(ilib.getLocale());
22192 	
22193 	/** @private */
22194 	this.caseFirst = "upper";
22195 	/** @private */
22196 	this.sensitivity = "variant";
22197 	/** @private */
22198 	this.level = 4;
22199 	/** @private */
22200 	this.usage = "sort";
22201 	/** @private */
22202 	this.reverse = false;
22203 	/** @private */
22204 	this.numeric = false;
22205 	/** @private */
22206 	this.style = "standard";
22207 	/** @private */
22208 	this.ignorePunctuation = false;
22209 	
22210 	if (options) {
22211 		if (options.locale) {
22212 			this.locale = (typeof(options.locale) === 'string') ? new ilib.Locale(options.locale) : options.locale;
22213 		}
22214 		if (options.sensitivity) {
22215 			switch (options.sensitivity) {
22216 				case 'primary':
22217 				case 'base':
22218 					this.sensitivity = "base";
22219 					this.level = 1;
22220 					break;
22221 				case 'secondary':
22222 				case 'case':
22223 					this.sensitivity = "case";
22224 					this.level = 2;
22225 					break;
22226 				case 'tertiary':
22227 				case 'accent':
22228 					this.sensitivity = "accent";
22229 					this.level = 3;
22230 					break;
22231 				case 'quaternary':
22232 				case 'variant':
22233 					this.sensitivity = "variant";
22234 					this.level = 4;
22235 					break;
22236 			}
22237 		}
22238 		if (typeof(options.upperFirst) !== 'undefined') {
22239 			this.caseFirst = options.upperFirst ? "upper" : "lower"; 
22240 		}
22241 		
22242 		if (typeof(options.ignorePunctuation) !== 'undefined') {
22243 			this.ignorePunctuation = options.ignorePunctuation;
22244 		}
22245 		if (typeof(options.sync) !== 'undefined') {
22246 			sync = (options.sync == true);
22247 		}
22248 		
22249 		loadParams = options.loadParams;
22250 		if (typeof(options.useNative) !== 'undefined') {
22251 			useNative = options.useNative;
22252 		}
22253 		
22254 		if (options.usage === "sort" || options.usage === "search") {
22255 			this.usage = options.usage;
22256 		}
22257 		
22258 		if (typeof(options.reverse) === 'boolean') {
22259 			this.reverse = options.reverse;
22260 		}
22261 
22262 		if (typeof(options.numeric) === 'boolean') {
22263 			this.numeric = options.numeric;
22264 		}
22265 		
22266 		if (typeof(options.style) === 'string') {
22267 			this.style = options.style;
22268 		}
22269 	}
22270 
22271 	if (this.usage === "sort") {
22272 		// produces a stable sort
22273 		this.level = 4;
22274 	}
22275 
22276 	if (useNative && typeof(Intl) !== 'undefined' && Intl) {
22277 		// this engine is modern and supports the new Intl object!
22278 		//console.log("implemented natively");
22279 		/** 
22280 		 * @private
22281 		 * @type {{compare:function(string,string)}} 
22282 		 */
22283 		this.collator = new Intl.Collator(this.locale.getSpec(), this);
22284 		
22285 		if (options && typeof(options.onLoad) === 'function') {
22286 			options.onLoad(this);
22287 		}
22288 	} else {
22289 		//console.log("implemented in pure JS");
22290 		if (!ilib.Collator.cache) {
22291 			ilib.Collator.cache = {};
22292 		}
22293 
22294 		// else implement in pure Javascript
22295 		ilib.loadData({
22296 			object: ilib.Collator, 
22297 			locale: this.locale, 
22298 			name: "collation.json",
22299 			replace: true,
22300 			sync: sync,
22301 			loadParams: loadParams, 
22302 			callback: ilib.bind(this, function (collation) {
22303 				if (!collation) {
22304 					collation = ilib.data.collation;
22305 					var spec = this.locale.getSpec().replace(/-/g, '_');
22306 					ilib.Collator.cache[spec] = collation;
22307 				}
22308 				this._init(collation);
22309 				new ilib.LocaleInfo(this.locale, {
22310 					sync: sync,
22311 					loadParams: loadParams,
22312 					onLoad: ilib.bind(this, function(li) {
22313 						this.li = li;
22314 						if (this.ignorePunctuation) {
22315 			    			ilib.CType.isPunct._init(sync, loadParams, ilib.bind(this, function() {
22316 								if (options && typeof(options.onLoad) === 'function') {
22317 									options.onLoad(this);
22318 								}
22319 			    			}));
22320 		    			} else {
22321 							if (options && typeof(options.onLoad) === 'function') {
22322 								options.onLoad(this);
22323 							}
22324 		    			}
22325 		    		})
22326 				});
22327 			})
22328 		});
22329 	}
22330 };
22331 
22332 ilib.Collator.prototype = {
22333 	/**
22334 	 * @private
22335 	 * Bit pack an array of values into a single number
22336 	 * @param {number|null|Array.<number>} arr array of values to bit pack
22337 	 */
22338 	_pack: function (arr) {
22339 		var value = 0;
22340 		if (arr) {
22341 			if (typeof(arr) === 'number') {
22342 				arr = [ arr ];
22343 			}
22344 			for (var i = 0; i < this.level; i++) {
22345 				if (i > 0) {
22346 					value <<= this.collation.bits[i];	
22347 				}
22348 				if (i === 2 && this.caseFirst === "lower") {
22349 					// sort the lower case first instead of upper
22350 					value = value | (1 - (typeof(arr[i]) !== "undefined" ? arr[i] : 0));
22351 				} else {
22352 					value = value | arr[i];
22353 				}
22354 			}
22355 		}
22356 		return value;
22357 	},
22358 	
22359 	/**
22360 	 * @private
22361 	 * Return the rule packed into an array of collation elements.
22362 	 * @param {Array.<number|null|Array.<number>>} rule
22363 	 * @return {Array.<number>} a bit-packed array of numbers
22364 	 */
22365 	_packRule: function(rule) {
22366 		if (rule[0] instanceof Array) {
22367 			var ret = [];
22368 			for (var i = 0; i < rule.length; i++) {
22369 				ret.push(this._pack(rule[i]));
22370 			}
22371 			return ret;
22372 		} else {
22373 			return [ this._pack(rule) ];
22374 		}
22375 	},
22376     	
22377 	/**
22378      * @private
22379      */
22380     _init: function(rules) {
22381     	/** 
22382     	 * @private
22383     	 * @type {{scripts:Array.<string>,bits:Array.<number>,maxes:Array.<number>,bases:Array.<number>,map:Object.<string,Array.<number|null|Array.<number>>>}}
22384     	 */
22385     	this.collation = rules[this.style];
22386     	this.map = {};
22387     	this.keysize = 0;
22388     	for (var i = 0; i < this.level; i++) {
22389     		this.keysize += this.collation.bits[i];
22390     	}
22391     	var remainder = ilib.mod(this.keysize, 4);
22392     	this.keysize += (remainder > 0) ? (4 - remainder) : 0; // round to the nearest 4 to find how many bits to use in hex
22393     	
22394     	for (var r in this.collation.map) {
22395     		if (r) {
22396     			this.map[r] = this._packRule(this.collation.map[r]);
22397     		}
22398     	}
22399     },
22400     
22401     /**
22402      * @private
22403      */
22404     _basicCompare: function(left, right) {
22405 		if (this.numeric) {
22406 			var lvalue = new ilib.Number(left, {locale: this.locale});
22407 			var rvalue = new ilib.Number(right, {locale: this.locale});
22408 			if (isNaN(lvalue.valueOf())) {
22409 				if (isNaN(rvalue.valueOf())) {
22410 					return 0;
22411 				}
22412 				return 1;
22413 			} else if (isNaN(rvalue.valueOf())) {
22414 				return -1;
22415 			}
22416 			return lvalue.valueOf() - rvalue.valueOf();
22417 		} else {
22418 			var l = (left instanceof ilib.NormString) ? left : new ilib.NormString(left),
22419 				r = (right instanceof ilib.NormString) ? right : new ilib.NormString(right),
22420 				lelements,
22421 				relements;
22422 				
22423 			// if the reverse sort is on, switch the char sources so that the result comes out swapped
22424 			lelements = new ilib.ElementIterator(new ilib.CodePointSource(l, this.ignorePunctuation), this.map, this.keysize);
22425 			relements = new ilib.ElementIterator(new ilib.CodePointSource(r, this.ignorePunctuation), this.map, this.keysize);
22426 			
22427 			while (lelements.hasNext() && relements.hasNext()) {
22428 				var diff = lelements.next() - relements.next();
22429 				if (diff) {
22430 					return diff;
22431 				}
22432 			}
22433 			if (!lelements.hasNext() && !relements.hasNext()) {
22434 				return 0;
22435 			} else if (lelements.hasNext()) {
22436 				return 1;
22437 			} else {
22438 				return -1;
22439 			}
22440 		}
22441     },
22442     
22443 	/**
22444 	 * Compare two strings together according to the rules of this 
22445 	 * collator instance. Do not use this function directly with 
22446 	 * Array.sort, as it will not have its collation data available
22447 	 * and therefore will not function properly. Use the function
22448 	 * returned by getComparator() instead.
22449 	 * 
22450 	 * @param {string} left the left string to compare
22451 	 * @param {string} right the right string to compare
22452 	 * @return {number} a negative number if left comes before right, a
22453 	 * positive number if right comes before left, and zero if left and 
22454 	 * right are equivalent according to this collator
22455 	 */
22456 	compare: function (left, right) {
22457 		// last resort: use the "C" locale
22458 		if (this.collator) {
22459 			// implemented by the core engine
22460 			return this.collator.compare(left, right);
22461 		}
22462 
22463 		var ret = this._basicCompare(left, right);
22464 		return this.reverse ? -ret : ret;
22465 	},
22466 	
22467 	/**
22468 	 * Return a comparator function that can compare two strings together
22469 	 * according to the rules of this collator instance. The function 
22470 	 * returns a negative number if the left 
22471 	 * string comes before right, a positive number if the right string comes 
22472 	 * before the left, and zero if left and right are equivalent. If the
22473 	 * reverse property was given as true to the collator constructor, this 
22474 	 * function will
22475 	 * switch the sign of those values to cause sorting to happen in the
22476 	 * reverse order.
22477 	 * 
22478 	 * @return {function(...)|undefined} a comparator function that 
22479 	 * can compare two strings together according to the rules of this 
22480 	 * collator instance
22481 	 */
22482 	getComparator: function() {
22483 		// bind the function to this instance so that we have the collation
22484 		// rules available to do the work
22485 		if (this.collator) {
22486 			// implemented by the core engine
22487 			return this.collator.compare;
22488 		}
22489 		
22490 		return /** @type function(string,string):number */ ilib.bind(this, this.compare);
22491 	},
22492 	
22493 	/**
22494 	 * Return a sort key string for the given string. The sort key
22495 	 * string is a list of values that represent each character 
22496 	 * in the original string. The sort key
22497 	 * values for any particular character consists of 3 numbers that
22498 	 * encode the primary, secondary, and tertiary characteristics
22499 	 * of that character. The values of each characteristic are 
22500 	 * modified according to the strength of this collator instance 
22501 	 * to give the correct collation order. The idea is that this
22502 	 * sort key string is directly comparable byte-for-byte to 
22503 	 * other sort key strings generated by this collator without
22504 	 * any further knowledge of the collation rules for the locale.
22505 	 * More formally, if a < b according to the rules of this collation, 
22506 	 * then it is guaranteed that sortkey(a) < sortkey(b) when compared
22507 	 * byte-for-byte. The sort key string can therefore be used
22508 	 * without the collator to sort an array of strings efficiently
22509 	 * because the work of determining the applicability of various
22510 	 * collation rules is done once up-front when generating 
22511 	 * the sort key.<p>
22512 	 * 
22513 	 * The sort key string can be treated as a regular, albeit somewhat
22514 	 * odd-looking, string. That is, it can be pass to regular 
22515 	 * Javascript functions without problems.  
22516 	 * 
22517 	 * @param {string} str the original string to generate the sort key for
22518 	 * @return {string} a sort key string for the given string
22519 	 */
22520 	sortKey: function (str) {
22521 		if (!str) {
22522 			return "";
22523 		}
22524 		
22525 		if (this.collator) {
22526 			// native, no sort keys available
22527 			return str;
22528 		}
22529 		
22530 		function pad(str, limit) {
22531 			return "0000000000000000".substring(0, limit - str.length) + str;
22532 		}
22533 		
22534 		if (this.numeric) {
22535 			var v = new ilib.Number(str, {locale: this.locale});
22536 			var s = isNaN(v.valueOf()) ? "" : v.valueOf().toString(16);
22537 			return pad(s, 16);	
22538 		} else {
22539 			var n = (typeof(str) === "string") ? new ilib.NormString(str) : str,
22540 				ret = "",
22541 				lelements = new ilib.ElementIterator(new ilib.CodePointSource(n, this.ignorePunctuation), this.map, this.keysize),
22542 				element;
22543 			
22544 			while (lelements.hasNext()) {
22545 				element = lelements.next();
22546 				if (this.reverse) {
22547 					element = (1 << this.keysize) - element;
22548 				}
22549 				ret += pad(element.toString(16), this.keysize/4);	
22550 			}
22551 		}
22552 		return ret;
22553 	}
22554 };
22555 
22556 /**
22557  * Retrieve the list of collation style names that are available for the 
22558  * given locale. This list varies depending on the locale, and depending
22559  * on whether or not the data for that locale was assembled into this copy
22560  * of ilib.
22561  * 
22562  * @param {ilib.Locale|string=} locale The locale for which the available
22563  * styles are being sought
22564  * @return Array.<string> an array of style names that are available for
22565  * the given locale
22566  */
22567 ilib.Collator.getAvailableStyles = function (locale) {
22568 	return [ "standard" ];
22569 };
22570 
22571 /**
22572  * Retrieve the list of ISO 15924 script codes that are available in this
22573  * copy of ilib. This list varies depending on whether or not the data for 
22574  * various scripts was assembled into this copy of ilib. If the "ducet"
22575  * data is assembled into this copy of ilib, this method will report the
22576  * entire list of scripts as being available. If a collator instance is
22577  * instantiated with a script code that is not on the list returned by this
22578  * function, it will be ignored and text in that script will be sorted by
22579  * numeric Unicode values of the characters.
22580  * 
22581  * @return Array.<string> an array of ISO 15924 script codes that are 
22582  * available
22583  */
22584 ilib.Collator.getAvailableScripts = function () {
22585 	return [ "Latn" ];
22586 };
22587 
22588 /*
22589  * all.js - include file for normalization data for a particular script
22590  * 
22591  * Copyright © 2012, JEDLSoft
22592  *
22593  * Licensed under the Apache License, Version 2.0 (the "License");
22594  * you may not use this file except in compliance with the License.
22595  * You may obtain a copy of the License at
22596  *
22597  *     http://www.apache.org/licenses/LICENSE-2.0
22598  *
22599  * Unless required by applicable law or agreed to in writing, software
22600  * distributed under the License is distributed on an "AS IS" BASIS,
22601  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22602  *
22603  * See the License for the specific language governing permissions and
22604  * limitations under the License.
22605  */
22606 /* WARNING: THIS IS A FILE GENERATED BY gennorm.js. DO NOT EDIT BY HAND. */
22607 // !depends util/utils.js 
22608 // !data norm nfd/all
22609 ilib.data.norm.nfd = ilib.merge(ilib.data.norm.nfd || {}, ilib.data.nfd_all);
22610 ilib.data.nfd_all = undefined;
22611 /*
22612  * all.js - include file for normalization data for a particular script
22613  * 
22614  * Copyright © 2012, JEDLSoft
22615  *
22616  * Licensed under the Apache License, Version 2.0 (the "License");
22617  * you may not use this file except in compliance with the License.
22618  * You may obtain a copy of the License at
22619  *
22620  *     http://www.apache.org/licenses/LICENSE-2.0
22621  *
22622  * Unless required by applicable law or agreed to in writing, software
22623  * distributed under the License is distributed on an "AS IS" BASIS,
22624  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22625  *
22626  * See the License for the specific language governing permissions and
22627  * limitations under the License.
22628  */
22629 /* WARNING: THIS IS A FILE GENERATED BY gennorm.js. DO NOT EDIT BY HAND. */
22630 // !depends util/utils.js 
22631 // !depends nfd/all.js
22632 // !data norm
22633 
22634 /*
22635  * all.js - include file for normalization data for a particular script
22636  * 
22637  * Copyright © 2012, JEDLSoft
22638  *
22639  * Licensed under the Apache License, Version 2.0 (the "License");
22640  * you may not use this file except in compliance with the License.
22641  * You may obtain a copy of the License at
22642  *
22643  *     http://www.apache.org/licenses/LICENSE-2.0
22644  *
22645  * Unless required by applicable law or agreed to in writing, software
22646  * distributed under the License is distributed on an "AS IS" BASIS,
22647  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22648  *
22649  * See the License for the specific language governing permissions and
22650  * limitations under the License.
22651  */
22652 /* WARNING: THIS IS A FILE GENERATED BY gennorm.js. DO NOT EDIT BY HAND. */
22653 // !depends util/utils.js 
22654 // !depends nfd/all.js
22655 // !data norm nfkd/all
22656 ilib.data.norm.nfkd = ilib.merge(ilib.data.norm.nfkd || {}, ilib.data.nfkd_all);
22657 ilib.data.nfkd_all = undefined;
22658 /*
22659  * all.js - include file for normalization data for a particular script
22660  * 
22661  * Copyright © 2012, JEDLSoft
22662  *
22663  * Licensed under the Apache License, Version 2.0 (the "License");
22664  * you may not use this file except in compliance with the License.
22665  * You may obtain a copy of the License at
22666  *
22667  *     http://www.apache.org/licenses/LICENSE-2.0
22668  *
22669  * Unless required by applicable law or agreed to in writing, software
22670  * distributed under the License is distributed on an "AS IS" BASIS,
22671  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22672  *
22673  * See the License for the specific language governing permissions and
22674  * limitations under the License.
22675  */
22676 /* WARNING: THIS IS A FILE GENERATED BY gennorm.js. DO NOT EDIT BY HAND. */
22677 // !depends util/utils.js 
22678 // !depends nfd/all.js nfc/all.js nfkd/all.js
22679 // !data norm
22680 
22681 /*
22682  * localematch.js - Locale matcher definition
22683  * 
22684  * Copyright © 2013-2014, JEDLSoft
22685  *
22686  * Licensed under the Apache License, Version 2.0 (the "License");
22687  * you may not use this file except in compliance with the License.
22688  * You may obtain a copy of the License at
22689  *
22690  *     http://www.apache.org/licenses/LICENSE-2.0
22691  *
22692  * Unless required by applicable law or agreed to in writing, software
22693  * distributed under the License is distributed on an "AS IS" BASIS,
22694  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22695  *
22696  * See the License for the specific language governing permissions and
22697  * limitations under the License.
22698  */
22699 
22700 // !depends ilibglobal.js locale.js
22701 // !data likelylocales
22702 
22703 /**
22704  * @class
22705  * Create a new locale matcher instance. This is used
22706  * to see which locales can be matched with each other in
22707  * various ways.<p>
22708  * 
22709  * The options object may contain any of the following properties:
22710  * 
22711  * <ul>
22712  * <li><i>locale</i> - the locale to match
22713  * 
22714  * <li><i>onLoad</i> - a callback function to call when the locale matcher object is fully 
22715  * loaded. When the onLoad option is given, the locale matcher object will attempt to
22716  * load any missing locale data using the ilib loader callback.
22717  * When the constructor is done (even if the data is already preassembled), the 
22718  * onLoad function is called with the current instance as a parameter, so this
22719  * callback can be used with preassembled or dynamic loading or a mix of the two.
22720  * 
22721  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
22722  * asynchronously. If this option is given as "false", then the "onLoad"
22723  * callback must be given, as the instance returned from this constructor will
22724  * not be usable for a while. 
22725  *
22726  * <li><i>loadParams</i> - an object containing parameters to pass to the 
22727  * loader callback function when locale data is missing. The parameters are not
22728  * interpretted or modified in any way. They are simply passed along. The object 
22729  * may contain any property/value pairs as long as the calling code is in
22730  * agreement with the loader callback function as to what those parameters mean.
22731  * </ul>
22732  * 
22733  * Depends directive: !depends localematch.js
22734  * 
22735  * @constructor
22736  * @param {Object} options parameters to initialize this matcher 
22737  */
22738 ilib.LocaleMatcher = function(options) {
22739 	var sync = true,
22740 	    loadParams = undefined;
22741 	
22742 	this.locale = new ilib.Locale();
22743 	
22744 	if (options) {
22745 		if (typeof(options.locale) !== 'undefined') {
22746 			this.locale = (typeof(options.locale) === 'string') ? new ilib.Locale(options.locale) : options.locale;
22747 		}
22748 		
22749 		if (typeof(options.sync) !== 'undefined') {
22750 			sync = (options.sync == true);
22751 		}
22752 		
22753 		if (typeof(options.loadParams) !== 'undefined') {
22754 			loadParams = options.loadParams;
22755 		}
22756 	}
22757 
22758 	if (!ilib.LocaleMatcher.cache) {
22759 		ilib.LocaleMatcher.cache = {};
22760 	}
22761 
22762 	if (typeof(ilib.data.likelylocales) === 'undefined') {
22763 		ilib.loadData({
22764 			object: ilib.LocaleMatcher, 
22765 			locale: "-", 
22766 			name: "likelylocales.json", 
22767 			sync: sync, 
22768 			loadParams: loadParams, 
22769 			callback: ilib.bind(this, function (info) {
22770 				if (!info) {
22771 					info = {};
22772 					var spec = this.locale.getSpec().replace(/-/g, "_");
22773 					ilib.LocaleMatcher.cache[spec] = info;
22774 				}
22775 				/** @type {Object.<string,string>} */
22776 				this.info = info;
22777 				if (options && typeof(options.onLoad) === 'function') {
22778 					options.onLoad(this);
22779 				}
22780 			})
22781 		});
22782 	} else {
22783 		this.info = /** @type {Object.<string,string>} */ ilib.data.likelylocales;
22784 	}
22785 };
22786 
22787 
22788 ilib.LocaleMatcher.prototype = {
22789 	/**
22790 	 * Return the locale used to construct this instance. 
22791 	 * @return {ilib.Locale|undefined} the locale for this matcher
22792 	 */
22793 	getLocale: function() {
22794 		return this.locale;
22795 	},
22796 	
22797 	/**
22798 	 * Return an ilib.Locale instance that is fully specified based on partial information
22799 	 * given to the constructor of this locale matcher instance. For example, if the locale
22800 	 * spec given to this locale matcher instance is simply "ru" (for the Russian language), 
22801 	 * then it will fill in the missing region and script tags and return a locale with 
22802 	 * the specifier "ru-Cyrl-RU". (ie. Russian language, Cyrillic, Russian Federation).
22803 	 * Any one or two of the language, script, or region parts may be left unspecified,
22804 	 * and the other one or two parts will be filled in automatically. If this
22805 	 * class has no information about the given locale, then the locale of this
22806 	 * locale matcher instance is returned unchanged.
22807 	 * 
22808 	 * @returns {ilib.Locale} the most likely completion of the partial locale given
22809 	 * to the constructor of this locale matcher instance
22810 	 */
22811 	getLikelyLocale: function () {
22812 		if (typeof(this.info[this.locale.getSpec()]) === 'undefined') {
22813 			return this.locale;
22814 		}
22815 		
22816 		return new ilib.Locale(this.info[this.locale.getSpec()]);
22817 	}
22818 };
22819 
22820 
22821 /*
22822  * casemapper.js - define upper- and lower-case mapper
22823  * 
22824  * Copyright © 2014-2015, JEDLSoft
22825  *
22826  * Licensed under the Apache License, Version 2.0 (the "License");
22827  * you may not use this file except in compliance with the License.
22828  * You may obtain a copy of the License at
22829  *
22830  *     http://www.apache.org/licenses/LICENSE-2.0
22831  *
22832  * Unless required by applicable law or agreed to in writing, software
22833  * distributed under the License is distributed on an "AS IS" BASIS,
22834  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22835  *
22836  * See the License for the specific language governing permissions and
22837  * limitations under the License.
22838  */
22839 
22840 // !depends locale.js util/utils.js
22841 
22842 /**
22843  * @class
22844  * Create a new string mapper instance that maps strings to upper or
22845  * lower case. This mapping will work for any string as characters 
22846  * that have no case will be returned unchanged.<p>
22847  * 
22848  * The options may contain any of the following properties:
22849  * 
22850  * <ul>
22851  * <li><i>locale</i> - locale to use when loading the mapper. Some maps are 
22852  * locale-dependent, and this locale selects the right one. Default if this is
22853  * not specified is the current locale.
22854  * 
22855  * <li><i>direction</i> - "toupper" for upper-casing, or "tolower" for lower-casing.
22856  * Default if not specified is "toupper".
22857  * </ul>
22858  * 
22859  * Depends directive: !depends casemapper.js
22860  * 
22861  * @constructor
22862  * @param {Object=} options options to initialize this mapper 
22863  */
22864 ilib.CaseMapper = function (options) {
22865 	this.up = true;
22866 	this.locale = new ilib.Locale();
22867 	
22868 	if (options) {
22869 		if (typeof(options.locale) !== 'undefined') {
22870 			this.locale = (typeof(options.locale) === 'string') ? new ilib.Locale(options.locale) : options.locale;
22871 		}
22872 		
22873 		this.up = (!options.direction || options.direction === "toupper");
22874 	}
22875 
22876 	this.mapData = this.up ? {
22877 		"ß": "SS",		// German
22878 		'ΐ': 'Ι',		// Greek
22879 		'ά': 'Α',
22880 		'έ': 'Ε',
22881 		'ή': 'Η',
22882 		'ί': 'Ι',
22883 		'ΰ': 'Υ',
22884 		'ϊ': 'Ι',
22885 		'ϋ': 'Υ',
22886 		'ό': 'Ο',
22887 		'ύ': 'Υ',
22888 		'ώ': 'Ω',
22889 		'Ӏ': 'Ӏ',		// Russian and slavic languages
22890 		'ӏ': 'Ӏ'
22891 	} : {
22892 		'Ӏ': 'Ӏ'		// Russian and slavic languages
22893 	};
22894 
22895 	switch (this.locale.getLanguage()) {
22896 		case "az":
22897 		case "tr":
22898 		case "crh":
22899 		case "kk":
22900 		case "krc":
22901 		case "tt":
22902 			var lower = "iı";
22903 			var upper = "İI";
22904 			this._setUpMap(lower, upper);
22905 			break;
22906 		case "fr":
22907 			if (this.up && this.locale.getRegion() !== "CA") {
22908 				this._setUpMap("àáâãäçèéêëìíîïñòóôöùúûü", "AAAAACEEEEIIIINOOOOUUUU");
22909 			}
22910 			break;
22911 	}
22912 	
22913 	if (ilib._getBrowser() === "ie") {
22914 		// IE is missing these mappings for some reason
22915 		if (this.up) {
22916 			this.mapData['ς'] = 'Σ';
22917 		}
22918 		this._setUpMap("ⲁⲃⲅⲇⲉⲋⲍⲏⲑⲓⲕⲗⲙⲛⲝⲟⲡⲣⲥⲧⲩⲫⲭⲯⲱⳁⳉⳋ", "ⲀⲂⲄⲆⲈⲊⲌⲎⲐⲒⲔⲖⲘⲚⲜⲞⲠⲢⲤⲦⲨⲪⲬⲮⲰⳀⳈⳊ"); // Coptic
22919 		// Georgian Nuskhuri <-> Asomtavruli
22920 		this._setUpMap("ⴀⴁⴂⴃⴄⴅⴆⴇⴈⴉⴊⴋⴌⴍⴎⴏⴐⴑⴒⴓⴔⴕⴖⴗⴘⴙⴚⴛⴜⴝⴞⴟⴠⴡⴢⴣⴤⴥ", "ႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅ");	
22921 	}
22922 };
22923 
22924 ilib.CaseMapper.prototype = {
22925 	/** 
22926 	 * @private 
22927 	 */
22928 	_charMapper: function(string) {
22929 		if (!string) {
22930 			return string;
22931 		}
22932 		var input = (typeof(string) === 'string') ? new ilib.String(string) : string.toString();
22933 		var ret = "";
22934 		var it = input.charIterator();
22935 		var c;
22936 		
22937 		while (it.hasNext()) {
22938 			c = it.next();
22939 			if (!this.up && c === 'Σ') {
22940 				if (it.hasNext()) {
22941 					c = it.next();
22942 					var code = c.charCodeAt(0);
22943 					// if the next char is not a greek letter, this is the end of the word so use the
22944 					// final form of sigma. Otherwise, use the mid-word form.
22945 					ret += ((code < 0x0388 && code !== 0x0386) || code > 0x03CE) ? 'ς' : 'σ';
22946 					ret += c.toLowerCase();
22947 				} else {
22948 					// no next char means this is the end of the word, so use the final form of sigma
22949 					ret += 'ς';
22950 				}
22951 			} else {
22952 				if (this.mapData[c]) {
22953 					ret += this.mapData[c];
22954 				} else {
22955 					ret += this.up ? c.toUpperCase() : c.toLowerCase();
22956 				}
22957 			}
22958 		}
22959 		
22960 		return ret;
22961 	},
22962 
22963 	/** @private */
22964 	_setUpMap: function(lower, upper) {
22965 		var from, to;
22966 		if (this.up) {
22967 			from = lower;
22968 			to = upper;
22969 		} else {
22970 			from = upper;
22971 			to = lower;
22972 		}
22973 		for (var i = 0; i < upper.length; i++) {
22974 			this.mapData[from[i]] = to[i];
22975 		}
22976 	},
22977 
22978 	/**
22979 	 * Return the locale that this mapper was constructed with. 
22980 	 * @returns {ilib.Locale} the locale that this mapper was constructed with
22981 	 */
22982 	getLocale: function () {
22983 		return this.locale;
22984 	},
22985 		
22986 	/**
22987 	 * Map a string to lower case in a locale-sensitive manner.
22988 	 * 
22989 	 * @param {string|undefined} string
22990 	 * @return {string|undefined}
22991 	 */
22992 	map: function (string) {
22993 		return this._charMapper(string);
22994 	}
22995 };
22996 /*
22997  * numplan.js - Represent a phone numbering plan.
22998  * 
22999  * Copyright © 2014, JEDLSoft
23000  *
23001  * Licensed under the Apache License, Version 2.0 (the "License");
23002  * you may not use this file except in compliance with the License.
23003  * You may obtain a copy of the License at
23004  *
23005  *     http://www.apache.org/licenses/LICENSE-2.0
23006  *
23007  * Unless required by applicable law or agreed to in writing, software
23008  * distributed under the License is distributed on an "AS IS" BASIS,
23009  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23010  *
23011  * See the License for the specific language governing permissions and
23012  * limitations under the License.
23013  */
23014 
23015 /*
23016 !depends 
23017 ilibglobal.js 
23018 locale.js 
23019 localeinfo.js
23020 */
23021 
23022 // !data numplan
23023 
23024 /**
23025  * @class
23026  * Create a numbering plan information instance for a particular country's plan.<p>
23027  * 
23028  * The options may contain any of the following properties:
23029  * 
23030  * <ul>
23031  * <li><i>locale</i> - locale for which the numbering plan is sought. This locale
23032  * will be mapped to the actual numbering plan, which may be shared amongst a
23033  * number of countries.
23034  *
23035  * <li>onLoad - a callback function to call when the date format object is fully 
23036  * loaded. When the onLoad option is given, the DateFmt object will attempt to
23037  * load any missing locale data using the ilib loader callback.
23038  * When the constructor is done (even if the data is already preassembled), the 
23039  * onLoad function is called with the current instance as a parameter, so this
23040  * callback can be used with preassembled or dynamic loading or a mix of the two.
23041  * 
23042  * <li>sync - tell whether to load any missing locale data synchronously or 
23043  * asynchronously. If this option is given as "false", then the "onLoad"
23044  * callback must be given, as the instance returned from this constructor will
23045  * not be usable for a while.
23046  *  
23047  * <li><i>loadParams</i> - an object containing parameters to pass to the 
23048  * loader callback function when locale data is missing. The parameters are not
23049  * interpretted or modified in any way. They are simply passed along. The object 
23050  * may contain any property/value pairs as long as the calling code is in
23051  * agreement with the loader callback function as to what those parameters mean.
23052  * </ul>
23053  * 
23054  * Depends directive: !depends phone/numplan.js
23055  * 
23056  * @constructor
23057  * @package
23058  * @param {Object} options options governing the way this plan is loaded
23059  */
23060 ilib.NumPlan = function (options) {
23061 	var sync = true,
23062 	    loadParams = {};
23063 	
23064 	this.locale = new ilib.Locale();
23065 
23066 	if (options) {
23067 		if (options.locale) {
23068 			this.locale = (typeof(options.locale) === 'string') ? new ilib.Locale(options.locale) : options.locale;
23069 		}
23070 		
23071 		if (typeof(options.sync) !== 'undefined') {
23072 			sync = (options.sync == true);
23073 		}
23074 		
23075 		if (options.loadParams) {
23076 			loadParams = options.loadParams;
23077 		}
23078 	}	
23079 
23080 	ilib.loadData({
23081 		name: "numplan.json",
23082 		object: ilib.NumPlan,
23083 		locale: this.locale,
23084 		sync: sync, 
23085 		loadParams: loadParams, 
23086 		callback: ilib.bind(this, function (npdata) {
23087 			if (!npdata) {
23088 				npdata = {
23089 					"region": "XX",
23090 					"skipTrunk": false,
23091 					"trunkCode": "0",
23092 					"iddCode": "00",
23093 					"dialingPlan": "closed",
23094 					"commonFormatChars": " ()-./",
23095 					"fieldLengths": {
23096 						"areaCode": 0,
23097 						"cic": 0,
23098 						"mobilePrefix": 0,
23099 						"serviceCode": 0
23100 					}
23101 				};
23102 			}
23103 
23104 			/** 
23105 			 * @type {{
23106 			 *   region:string,
23107 			 *   skipTrunk:boolean,
23108 			 *   trunkCode:string,
23109 			 *   iddCode:string,
23110 			 *   dialingPlan:string,
23111 			 *   commonFormatChars:string,
23112 			 *   fieldLengths:Object.<string,number>,
23113 			 *   contextFree:boolean,
23114 			 *   findExtensions:boolean,
23115 			 *   trunkRequired:boolean,
23116 			 *   extendedAreaCodes:boolean
23117 			 * }}
23118 			 */
23119 			this.npdata = npdata;
23120 			if (options && typeof(options.onLoad) === 'function') {
23121 				options.onLoad(this);
23122 			}
23123 		})
23124 	});
23125 };
23126 
23127 ilib.NumPlan.prototype = {
23128 	/**
23129 	 * Return the name of this plan. This may be different than the 
23130 	 * name of the region because sometimes multiple countries share 
23131 	 * the same plan.
23132 	 * @return {string} the name of the plan
23133 	 */
23134 	getName: function() {
23135 		return this.npdata.region;
23136 	},
23137 
23138 	/**
23139 	 * Return the trunk code of the current plan as a string.
23140 	 * @return {string|undefined} the trunk code of the plan or
23141 	 * undefined if there is no trunk code in this plan
23142 	 */
23143 	getTrunkCode: function() {
23144 		return this.npdata.trunkCode;
23145 	},
23146 	
23147 	/**
23148 	 * Return the international direct dialing code of this plan.
23149 	 * @return {string} the IDD code of this plan
23150 	 */
23151 	getIDDCode: function() {
23152 		return this.npdata.iddCode;	
23153 	},
23154 	
23155 	/**
23156 	 * Return the plan style for this plan. The plan style may be
23157 	 * one of:
23158 	 * 
23159 	 * <ul>
23160 	 * <li>"open" - area codes may be left off if the caller is 
23161 	 * dialing to another number within the same area code
23162 	 * <li>"closed" - the area code must always be specified, even
23163 	 * if calling another number within the same area code
23164 	 * </ul>
23165 	 * 
23166 	 * @return {string} the plan style, "open" or "closed"
23167 	 */
23168 	getPlanStyle: function() {	
23169 		return this.npdata.dialingPlan;
23170 	},
23171 	/** [Need Comment]
23172 	 * Return a contextFree
23173 	 *
23174 	 * @return {boolean}
23175 	 */
23176 	getContextFree: function() {
23177 		return this.npdata.contextFree;
23178 	},
23179 	/** [Need Comment]
23180 	 * Return a findExtensions
23181 	 * 
23182 	 * @return {boolean}
23183 	 */
23184 	getFindExtensions: function() {
23185 		return this.npdata.findExtensions;
23186 	},
23187 	/** [Need Comment]
23188 	 * Return a skipTrunk
23189 	 * 
23190 	 * @return {boolean}
23191 	 */
23192 	getSkipTrunk: function() {
23193 		return this.npdata.skipTrunk;
23194 	},
23195 	/** [Need Comment]
23196 	 * Return a skipTrunk
23197 	 * 
23198 	 * @return {boolean}
23199 	 */
23200 	getTrunkRequired: function() {
23201 		return this.npdata.trunkRequired;
23202 	},
23203 	/**
23204 	 * Return true if this plan uses extended area codes.
23205 	 * @return {boolean} true if the plan uses extended area codes
23206 	 */
23207 	getExtendedAreaCode: function() {
23208 		return this.npdata.extendedAreaCodes;
23209 	},
23210 	/**
23211 	 * Return a string containing all of the common format characters
23212 	 * used to format numbers.
23213 	 * @return {string} the common format characters fused in this locale
23214 	 */
23215 	getCommonFormatChars: function() {
23216 		return this.npdata.commonFormatChars;
23217 	},
23218 	
23219 	/**
23220 	 * Return the length of the field with the given name. If the length
23221 	 * is returned as 0, this means it is variable length.
23222 	 * 
23223 	 * @param {string} field name of the field for which the length is 
23224 	 * being sought
23225 	 * @return {number} if positive, this gives the length of the given 
23226 	 * field. If zero, the field is variable length. If negative, the
23227 	 * field is not known.
23228 	 */
23229 	getFieldLength: function (field) {
23230 		var dataField = this.npdata.fieldLengths;
23231 		
23232 		return dataField[field];
23233 	}
23234 };
23235 
23236 /*
23237  * phoneloc.js - Represent a phone locale object.
23238  * 
23239  * Copyright © 2014, JEDLSoft
23240  *
23241  * Licensed under the Apache License, Version 2.0 (the "License");
23242  * you may not use this file except in compliance with the License.
23243  * You may obtain a copy of the License at
23244  *
23245  *     http://www.apache.org/licenses/LICENSE-2.0
23246  *
23247  * Unless required by applicable law or agreed to in writing, software
23248  * distributed under the License is distributed on an "AS IS" BASIS,
23249  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23250  *
23251  * See the License for the specific language governing permissions and
23252  * limitations under the License.
23253  */
23254 
23255 /*
23256 !depends 
23257 ilibglobal.js 
23258 locale.js 
23259 localeinfo.js
23260 */
23261 
23262 // !data phoneloc
23263 
23264 /**
23265  * @class
23266  *
23267  * @param {Object} options Options that govern how this phone locale works
23268  * @constructor
23269  * @private
23270  * @extends ilib.Locale
23271  */
23272 ilib.Locale.PhoneLoc = function(options) {
23273 	var region,
23274 		mcc,
23275 		cc,
23276 		sync = true,
23277 		loadParams = {},
23278 		locale;
23279 	
23280 	locale = (options && options.locale) || ilib.getLocale();
23281 
23282 	this.parent.call(this, locale);
23283 	
23284 	region = this.region;
23285 	
23286 	if (options) {
23287 		if (typeof(options.mcc) !== 'undefined') {
23288 			mcc = options.mcc;
23289 		}
23290 		
23291 		if (typeof(options.countryCode) !== 'undefined') {
23292 			cc = options.countryCode;
23293 		}
23294 
23295 		if (typeof(options.sync) !== 'undefined') {
23296 			sync = (options.sync == true);
23297 		}
23298 		
23299 		if (options.loadParams) {
23300 			loadParams = options.loadParams;
23301 		}
23302 	}
23303 
23304 	ilib.loadData({
23305 		name: "phoneloc.json",
23306 		object: ilib.Locale.PhoneLoc,
23307 		nonlocale: true,
23308 		sync: sync, 
23309 		loadParams: loadParams, 
23310 		callback: ilib.bind(this, function (data) {
23311 			/** @type {{mcc2reg:Object.<string,string>,cc2reg:Object.<string,string>,reg2cc:Object.<string,string>,area2reg:Object.<string,string>}} */
23312 			this.mappings = data;
23313 			
23314 			if (typeof(mcc) !== 'undefined') {
23315 				region = this.mappings.mcc2reg[mcc];	
23316 			}
23317 
23318 			if (typeof(cc) !== 'undefined') {
23319 				region = this.mappings.cc2reg[cc];
23320 			}
23321 
23322 			if (!region) {
23323 				region = "XX";
23324 			}
23325 
23326 			this.region = this._normPhoneReg(region);
23327 			this._genSpec();
23328 
23329 			if (options && typeof(options.onLoad) === 'function') {
23330 				options.onLoad(this);
23331 			}									
23332 		})
23333 	});
23334 };
23335 
23336 ilib.Locale.PhoneLoc.prototype = new ilib.Locale();
23337 ilib.Locale.PhoneLoc.prototype.parent = ilib.Locale;
23338 ilib.Locale.PhoneLoc.prototype.constructor = ilib.Locale.PhoneLoc;
23339 
23340 /**
23341  * Map a mobile carrier code to a region code.
23342  *
23343  * @static
23344  * @package
23345  * @param {string|undefined} mcc the MCC to map
23346  * @return {string|undefined} the region code
23347  */
23348 
23349 ilib.Locale.PhoneLoc.prototype._mapMCCtoRegion = function(mcc) {
23350 	if (!mcc) {
23351 		return undefined;
23352 	}
23353 	return this.mappings.mcc2reg && this.mappings.mcc2reg[mcc] || "XX";
23354 };
23355 
23356 /**
23357  * Map a country code to a region code.
23358  *
23359  * @static
23360  * @package
23361  * @param {string|undefined} cc the country code to map
23362  * @return {string|undefined} the region code
23363  */
23364 ilib.Locale.PhoneLoc.prototype._mapCCtoRegion = function(cc) {
23365 	if (!cc) {
23366 		return undefined;
23367 	}
23368 	return this.mappings.cc2reg && this.mappings.cc2reg[cc] || "XX";
23369 };
23370 
23371 /**
23372  * Map a region code to a country code.
23373  *
23374  * @static
23375  * @package
23376  * @param {string|undefined} region the region code to map
23377  * @return {string|undefined} the country code
23378  */
23379 ilib.Locale.PhoneLoc.prototype._mapRegiontoCC = function(region) {
23380 	if (!region) {
23381 		return undefined;
23382 	}
23383 	return this.mappings.reg2cc && this.mappings.reg2cc[region] || "0";
23384 };
23385 
23386 /**
23387  * Map a country code to a region code.
23388  *
23389  * @static
23390  * @package
23391  * @param {string|undefined} cc the country code to map
23392  * @param {string|undefined} area the area code within the country code's numbering plan
23393  * @return {string|undefined} the region code
23394  */
23395 ilib.Locale.PhoneLoc.prototype._mapAreatoRegion = function(cc, area) {
23396 	if (!cc) {
23397 		return undefined;
23398 	}
23399 	if (cc in this.mappings.area2reg) {
23400 		return this.mappings.area2reg[cc][area] || this.mappings.area2reg[cc]["default"];
23401 	} else {
23402 		return this.mappings.cc2reg[cc];
23403 	}
23404 };
23405 
23406 /**
23407  * Return the region that controls the dialing plan in the given
23408  * region. (ie. the "normalized phone region".)
23409  * 
23410  * @static
23411  * @package
23412  * @param {string} region the region code to normalize
23413  * @return {string} the normalized region code
23414  */
23415 ilib.Locale.PhoneLoc.prototype._normPhoneReg = function(region) {
23416 	var norm;
23417 	
23418 	// Map all NANP regions to the right region, so that they get parsed using the 
23419 	// correct state table
23420 	switch (region) {
23421 		case "US": // usa
23422 		case "CA": // canada
23423 		case "AG": // antigua and barbuda
23424 		case "BS": // bahamas
23425 		case "BB": // barbados
23426 		case "DM": // dominica
23427 		case "DO": // dominican republic
23428 		case "GD": // grenada
23429 		case "JM": // jamaica
23430 		case "KN": // st. kitts and nevis
23431 		case "LC": // st. lucia
23432 		case "VC": // st. vincent and the grenadines
23433 		case "TT": // trinidad and tobago
23434 		case "AI": // anguilla
23435 		case "BM": // bermuda
23436 		case "VG": // british virgin islands
23437 		case "KY": // cayman islands
23438 		case "MS": // montserrat
23439 		case "TC": // turks and caicos
23440 		case "AS": // American Samoa 
23441 		case "VI": // Virgin Islands, U.S.
23442 		case "PR": // Puerto Rico
23443 		case "MP": // Northern Mariana Islands
23444 		case "T:": // East Timor
23445 		case "GU": // Guam
23446 			norm = "US";
23447 			break;
23448 		
23449 		// these all use the Italian dialling plan
23450 		case "IT": // italy
23451 		case "SM": // san marino
23452 		case "VA": // vatican city
23453 			norm = "IT";
23454 			break;
23455 		
23456 		// all the French dependencies are on the French dialling plan
23457 		case "FR": // france
23458 		case "GF": // french guiana
23459 		case "MQ": // martinique
23460 		case "GP": // guadeloupe, 
23461 		case "BL": // saint barthélemy
23462 		case "MF": // saint martin
23463 		case "RE": // réunion, mayotte
23464 			norm = "FR";
23465 			break;
23466 		default:
23467 			norm = region;
23468 			break;
23469 	}	
23470 	return norm;
23471 };
23472 /*
23473  * handler.js - Handle phone number parse states
23474  * 
23475  * Copyright © 2014, JEDLSoft
23476  *
23477  * Licensed under the Apache License, Version 2.0 (the "License");
23478  * you may not use this file except in compliance with the License.
23479  * You may obtain a copy of the License at
23480  *
23481  *     http://www.apache.org/licenses/LICENSE-2.0
23482  *
23483  * Unless required by applicable law or agreed to in writing, software
23484  * distributed under the License is distributed on an "AS IS" BASIS,
23485  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23486  *
23487  * See the License for the specific language governing permissions and
23488  * limitations under the License.
23489  */
23490 
23491 /*
23492 !depends 
23493 ilibglobal.js 
23494 phone/phoneloc.js
23495 */
23496 
23497 /**
23498  * @class
23499  * [Need Comments] globals console ilib PhoneLoc 
23500  *
23501  * @private
23502  * @constructor
23503  */
23504 ilib.StateHandler = function _StateHandler () {
23505 	return this;
23506 };
23507 
23508 ilib.StateHandler.prototype = {
23509 	/**
23510 	 * @private
23511 	 * @param {string} number phone number
23512 	 * @param {Object} fields the fields that have been extracted so far
23513 	 * @param {Object} regionSettings settings used to parse the rest of the number
23514 	 */
23515 	processSubscriberNumber: function(number, fields, regionSettings) {
23516 		var last;
23517 		
23518 		last = number.search(/[xwtp,;]/i);	// last digit of the local number
23519 
23520 		if (last > -1) {
23521 			if (last > 0) {
23522 				fields.subscriberNumber = number.substring(0, last);
23523 			}
23524 			// strip x's which are there to indicate a break between the local subscriber number and the extension, but
23525 			// are not themselves a dialable character
23526 			fields.extension = number.substring(last).replace('x', '');
23527 		} else {
23528 			if (number.length) {
23529 				fields.subscriberNumber = number;
23530 			}
23531 		}
23532 		
23533 		if (regionSettings.plan.getFieldLength('maxLocalLength') &&
23534 				fields.subscriberNumber &&
23535 				fields.subscriberNumber.length > regionSettings.plan.getFieldLength('maxLocalLength')) {
23536 			fields.invalid = true;
23537 		}
23538 	},
23539 	/**
23540 	 * @private
23541 	 * @param {string} fieldName 
23542 	 * @param {number} length length of phone number
23543 	 * @param {string} number phone number
23544 	 * @param {number} currentChar currentChar to be parsed
23545 	 * @param {Object} fields the fields that have been extracted so far
23546 	 * @param {Object} regionSettings settings used to parse the rest of the number
23547 	 * @param {boolean} noExtractTrunk 
23548 	 */
23549 	processFieldWithSubscriberNumber: function(fieldName, length, number, currentChar, fields, regionSettings, noExtractTrunk) {
23550 		var ret, end;
23551 		
23552 		if (length !== undefined && length > 0) {
23553 			// fixed length
23554 			end = length;
23555 			if (regionSettings.plan.getTrunkCode() === "0" && number.charAt(0) === "0") {
23556 				end += regionSettings.plan.getTrunkCode().length;  // also extract the trunk access code
23557 			}
23558 		} else {
23559 			// variable length
23560 			// the setting is the negative of the length to add, so subtract to make it positive
23561 			end = currentChar + 1 - length;
23562 		}
23563 		
23564 		if (fields[fieldName] !== undefined) {
23565 			// we have a spurious recognition, because this number already contains that field! So, just put
23566 			// everything into the subscriberNumber as the default
23567 			this.processSubscriberNumber(number, fields, regionSettings);
23568 		} else {
23569 			fields[fieldName] = number.substring(0, end);
23570 			if (number.length > end) {
23571 				this.processSubscriberNumber(number.substring(end), fields, regionSettings);
23572 			}
23573 		}
23574 		
23575 		ret = {
23576 			number: ""
23577 		};
23578 
23579 		return ret;
23580 	},
23581 	/**
23582 	 * @private
23583 	 * @param {string} fieldName 
23584 	 * @param {number} length length of phone number
23585 	 * @param {string} number phone number
23586 	 * @param {number} currentChar currentChar to be parsed
23587 	 * @param {Object} fields the fields that have been extracted so far
23588 	 * @param {Object} regionSettings settings used to parse the rest of the number
23589 	 */
23590 	processField: function(fieldName, length, number, currentChar, fields, regionSettings) {
23591 		var ret = {}, end;
23592 		
23593 		if (length !== undefined && length > 0) {
23594 			// fixed length
23595 			end = length;
23596 			if (regionSettings.plan.getTrunkCode() === "0" && number.charAt(0) === "0") {
23597 				end += regionSettings.plan.getTrunkCode().length;  // also extract the trunk access code
23598 			}
23599 		} else {
23600 			// variable length
23601 			// the setting is the negative of the length to add, so subtract to make it positive
23602 			end = currentChar + 1 - length;
23603 		}
23604 		
23605 		if (fields[fieldName] !== undefined) {
23606 			// we have a spurious recognition, because this number already contains that field! So, just put
23607 			// everything into the subscriberNumber as the default
23608 			this.processSubscriberNumber(number, fields, regionSettings);
23609 			ret.number = "";
23610 		} else {
23611 			fields[fieldName] = number.substring(0, end);			
23612 			ret.number = (number.length > end) ? number.substring(end) : "";
23613 		}
23614 		
23615 		return ret;
23616 	},
23617 	/**
23618 	 * @private
23619 	 * @param {string} number phone number
23620 	 * @param {number} currentChar currentChar to be parsed
23621 	 * @param {Object} fields the fields that have been extracted so far
23622 	 * @param {Object} regionSettings settings used to parse the rest of the number
23623 	 */
23624 	trunk: function(number, currentChar, fields, regionSettings) {
23625 		var ret, trunkLength;
23626 		
23627 		if (fields.trunkAccess !== undefined) {
23628 			// What? We already have one? Okay, put the rest of this in the subscriber number as the default behaviour then.
23629 			this.processSubscriberNumber(number, fields, regionSettings);
23630 			number = "";
23631 		} else {
23632 			trunkLength = regionSettings.plan.getTrunkCode().length;
23633 			fields.trunkAccess = number.substring(0, trunkLength);
23634 			number = (number.length > trunkLength) ? number.substring(trunkLength) : "";
23635 		}
23636 		
23637 		ret = {
23638 			number: number
23639 		};
23640 		
23641 		return ret;
23642 	},
23643 	/**
23644 	 * @private
23645 	 * @param {string} number phone number
23646 	 * @param {number} currentChar currentChar to be parsed
23647 	 * @param {Object} fields the fields that have been extracted so far
23648 	 * @param {Object} regionSettings settings used to parse the rest of the number
23649 	 */
23650 	plus: function(number, currentChar, fields, regionSettings) {
23651 		var ret = {};
23652 		
23653 		if (fields.iddPrefix !== undefined) {
23654 			// What? We already have one? Okay, put the rest of this in the subscriber number as the default behaviour then.
23655 			this.processSubscriberNumber(number, fields, regionSettings);
23656 			ret.number = "";
23657 		} else {
23658 			// found the idd prefix, so save it and cause the function to parse the next part
23659 			// of the number with the idd table
23660 			fields.iddPrefix = number.substring(0, 1);
23661 	
23662 			ret = {
23663 				number: number.substring(1),
23664 				table: 'idd'    // shared subtable that parses the country code
23665 			};
23666 		}		
23667 		return ret;
23668 	},
23669 	/**
23670 	 * @private
23671 	 * @param {string} number phone number
23672 	 * @param {number} currentChar currentChar to be parsed
23673 	 * @param {Object} fields the fields that have been extracted so far
23674 	 * @param {Object} regionSettings settings used to parse the rest of the number
23675 	 */
23676 	idd: function(number, currentChar, fields, regionSettings) {
23677 		var ret = {};
23678 		
23679 		if (fields.iddPrefix !== undefined) {
23680 			// What? We already have one? Okay, put the rest of this in the subscriber number as the default behaviour then.
23681 			this.processSubscriberNumber(number, fields, regionSettings);
23682 			ret.number = "";
23683 		} else {
23684 			// found the idd prefix, so save it and cause the function to parse the next part
23685 			// of the number with the idd table
23686 			fields.iddPrefix = number.substring(0, currentChar+1);
23687 	
23688 			ret = {
23689 				number: number.substring(currentChar+1),
23690 				table: 'idd'    // shared subtable that parses the country code
23691 			};
23692 		}
23693 		
23694 		return ret;
23695 	},
23696 	/**
23697 	 * @private
23698 	 * @param {string} number phone number
23699 	 * @param {number} currentChar currentChar to be parsed
23700 	 * @param {Object} fields the fields that have been extracted so far
23701 	 * @param {Object} regionSettings settings used to parse the rest of the number
23702 	 */	
23703 	country: function(number, currentChar, fields, regionSettings) {
23704 		var ret, cc;
23705 		
23706 		// found the country code of an IDD number, so save it and cause the function to 
23707 		// parse the rest of the number with the regular table for this locale
23708 		fields.countryCode = number.substring(0, currentChar+1);
23709 		cc = fields.countryCode.replace(/[wWpPtT\+#\*]/g, ''); // fix for NOV-108200
23710 		// console.log("Found country code " + fields.countryCode + ". Switching to country " + locale.region + " to parse the rest of the number");
23711 		
23712 		ret = {
23713 			number: number.substring(currentChar+1),
23714 			countryCode: cc
23715 		};
23716 		
23717 		return ret;
23718 	},
23719 	/**
23720 	 * @private
23721 	 * @param {string} number phone number
23722 	 * @param {number} currentChar currentChar to be parsed
23723 	 * @param {Object} fields the fields that have been extracted so far
23724 	 * @param {Object} regionSettings settings used to parse the rest of the number
23725 	 */
23726 	cic: function(number, currentChar, fields, regionSettings) {
23727 		return this.processField('cic', regionSettings.plan.getFieldLength('cic'), number, currentChar, fields, regionSettings);
23728 	},
23729 	/**
23730 	 * @private
23731 	 * @param {string} number phone number
23732 	 * @param {number} currentChar currentChar to be parsed
23733 	 * @param {Object} fields the fields that have been extracted so far
23734 	 * @param {Object} regionSettings settings used to parse the rest of the number
23735 	 */
23736 	service: function(number, currentChar, fields, regionSettings) {
23737 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('serviceCode'), number, currentChar, fields, regionSettings, false);
23738 	},
23739 	/**
23740 	 * @private
23741 	 * @param {string} number phone number
23742 	 * @param {number} currentChar currentChar to be parsed
23743 	 * @param {Object} fields the fields that have been extracted so far
23744 	 * @param {Object} regionSettings settings used to parse the rest of the number
23745 	 */
23746 	area: function(number, currentChar, fields, regionSettings) {
23747 		var ret, last, end, localLength;
23748 		
23749 		last = number.search(/[xwtp]/i);	// last digit of the local number
23750 		localLength = (last > -1) ? last : number.length;
23751 
23752 		if (regionSettings.plan.getFieldLength('areaCode') > 0) {
23753 			// fixed length
23754 			end = regionSettings.plan.getFieldLength('areaCode');
23755 			if (regionSettings.plan.getTrunkCode() === number.charAt(0)) {
23756 				end += regionSettings.plan.getTrunkCode().length;  // also extract the trunk access code
23757 				localLength -= regionSettings.plan.getTrunkCode().length;
23758 			}
23759 		} else {
23760 			// variable length
23761 			// the setting is the negative of the length to add, so subtract to make it positive
23762 			end = currentChar + 1 - regionSettings.plan.getFieldLength('areaCode');
23763 		}
23764 		
23765 		// substring() extracts the part of the string up to but not including the end character,
23766 		// so add one to compensate
23767 		if (regionSettings.plan.getFieldLength('maxLocalLength') !== undefined) {
23768 			if (fields.trunkAccess !== undefined || fields.mobilePrefix !== undefined ||
23769 					fields.countryCode !== undefined ||
23770 					localLength > regionSettings.plan.getFieldLength('maxLocalLength')) {
23771 				// too long for a local number by itself, or a different final state already parsed out the trunk
23772 				// or mobile prefix, then consider the rest of this number to be an area code + part of the subscriber number
23773 				fields.areaCode = number.substring(0, end);
23774 				if (number.length > end) {
23775 					this.processSubscriberNumber(number.substring(end), fields, regionSettings);
23776 				}
23777 			} else {
23778 				// shorter than the length needed for a local number, so just consider it a local number
23779 				this.processSubscriberNumber(number, fields, regionSettings);
23780 			}
23781 		} else {
23782 			fields.areaCode = number.substring(0, end);
23783 			if (number.length > end) {
23784 				this.processSubscriberNumber(number.substring(end), fields, regionSettings);
23785 			}
23786 		}
23787 		
23788 		// extensions are separated from the number by a dash in Germany
23789 		if (regionSettings.plan.getFindExtensions() !== undefined && fields.subscriberNumber !== undefined) {
23790 			var dash = fields.subscriberNumber.indexOf("-");
23791 			if (dash > -1) {
23792 				fields.subscriberNumber = fields.subscriberNumber.substring(0, dash);
23793 				fields.extension = fields.subscriberNumber.substring(dash+1);
23794 			}
23795 		}
23796 
23797 		ret = {
23798 			number: ""
23799 		};
23800 
23801 		return ret;
23802 	},
23803 	/**
23804 	 * @private
23805 	 * @param {string} number phone number
23806 	 * @param {number} currentChar currentChar to be parsed
23807 	 * @param {Object} fields the fields that have been extracted so far
23808 	 * @param {Object} regionSettings settings used to parse the rest of the number
23809 	 */
23810 	none: function(number, currentChar, fields, regionSettings) {
23811 		var ret;
23812 		
23813 		// this is a last resort function that is called when nothing is recognized.
23814 		// When this happens, just put the whole stripped number into the subscriber number
23815 			
23816 		if (number.length > 0) {
23817 			this.processSubscriberNumber(number, fields, regionSettings);
23818 			if (currentChar > 0 && currentChar < number.length) {
23819 				// if we were part-way through parsing, and we hit an invalid digit,
23820 				// indicate that the number could not be parsed properly
23821 				fields.invalid = true;
23822 			}
23823 		}
23824 		
23825 		ret = {
23826 			number:""
23827 		};
23828 		
23829 		return ret;
23830 	},
23831 	/**
23832 	 * @private
23833 	 * @param {string} number phone number
23834 	 * @param {number} currentChar currentChar to be parsed
23835 	 * @param {Object} fields the fields that have been extracted so far
23836 	 * @param {Object} regionSettings settings used to parse the rest of the number
23837 	 */
23838 	vsc: function(number, currentChar, fields, regionSettings) {
23839 		var ret, length, end;
23840 
23841 		if (fields.vsc === undefined) {
23842 			length = regionSettings.plan.getFieldLength('vsc') || 0;
23843 			if (length !== undefined && length > 0) {
23844 				// fixed length
23845 				end = length;
23846 			} else {
23847 				// variable length
23848 				// the setting is the negative of the length to add, so subtract to make it positive
23849 				end = currentChar + 1 - length;
23850 			}
23851 			
23852 			// found a VSC code (ie. a "star code"), so save it and cause the function to 
23853 			// parse the rest of the number with the same table for this locale
23854 			fields.vsc = number.substring(0, end);
23855 			number = (number.length > end) ? "^" + number.substring(end) : "";
23856 		} else {
23857 			// got it twice??? Okay, this is a bogus number then. Just put everything else into the subscriber number as the default
23858 			this.processSubscriberNumber(number, fields, regionSettings);
23859 			number = "";
23860 		}
23861 
23862 		// treat the rest of the number as if it were a completely new number
23863 		ret = {
23864 			number: number
23865 		};
23866 
23867 		return ret;
23868 	},
23869 	/**
23870 	 * @private
23871 	 * @param {string} number phone number
23872 	 * @param {number} currentChar currentChar to be parsed
23873 	 * @param {Object} fields the fields that have been extracted so far
23874 	 * @param {Object} regionSettings settings used to parse the rest of the number
23875 	 */
23876 	cell: function(number, currentChar, fields, regionSettings) {
23877 		return this.processFieldWithSubscriberNumber('mobilePrefix', regionSettings.plan.getFieldLength('mobilePrefix'), number, currentChar, fields, regionSettings, false);
23878 	},
23879 	/**
23880 	 * @private
23881 	 * @param {string} number phone number
23882 	 * @param {number} currentChar currentChar to be parsed
23883 	 * @param {Object} fields the fields that have been extracted so far
23884 	 * @param {Object} regionSettings settings used to parse the rest of the number
23885 	 */
23886 	personal: function(number, currentChar, fields, regionSettings) {
23887 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('personal'), number, currentChar, fields, regionSettings, false);
23888 	},
23889 	/**
23890 	 * @private
23891 	 * @param {string} number phone number
23892 	 * @param {number} currentChar currentChar to be parsed
23893 	 * @param {Object} fields the fields that have been extracted so far
23894 	 * @param {Object} regionSettings settings used to parse the rest of the number
23895 	 */
23896 	emergency: function(number, currentChar, fields, regionSettings) {
23897 		return this.processFieldWithSubscriberNumber('emergency', regionSettings.plan.getFieldLength('emergency'), number, currentChar, fields, regionSettings, true);
23898 	},
23899 	/**
23900 	 * @private
23901 	 * @param {string} number phone number
23902 	 * @param {number} currentChar currentChar to be parsed
23903 	 * @param {Object} fields the fields that have been extracted so far
23904 	 * @param {Object} regionSettings settings used to parse the rest of the number
23905 	 */
23906 	premium: function(number, currentChar, fields, regionSettings) {
23907 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('premium'), number, currentChar, fields, regionSettings, false);
23908 	},
23909 	/**
23910 	 * @private
23911 	 * @param {string} number phone number
23912 	 * @param {number} currentChar currentChar to be parsed
23913 	 * @param {Object} fields the fields that have been extracted so far
23914 	 * @param {Object} regionSettings settings used to parse the rest of the number
23915 	 */
23916 	special: function(number, currentChar, fields, regionSettings) {
23917 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('special'), number, currentChar, fields, regionSettings, false);
23918 	},
23919 	/**
23920 	 * @private
23921 	 * @param {string} number phone number
23922 	 * @param {number} currentChar currentChar to be parsed
23923 	 * @param {Object} fields the fields that have been extracted so far
23924 	 * @param {Object} regionSettings settings used to parse the rest of the number
23925 	 */
23926 	service2: function(number, currentChar, fields, regionSettings) {
23927 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('service2'), number, currentChar, fields, regionSettings, false);
23928 	},
23929 	/**
23930 	 * @private
23931 	 * @param {string} number phone number
23932 	 * @param {number} currentChar currentChar to be parsed
23933 	 * @param {Object} fields the fields that have been extracted so far
23934 	 * @param {Object} regionSettings settings used to parse the rest of the number
23935 	 */
23936 	service3: function(number, currentChar, fields, regionSettings) {
23937 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('service3'), number, currentChar, fields, regionSettings, false);
23938 	},
23939 	/**
23940 	 * @private
23941 	 * @param {string} number phone number
23942 	 * @param {number} currentChar currentChar to be parsed
23943 	 * @param {Object} fields the fields that have been extracted so far
23944 	 * @param {Object} regionSettings settings used to parse the rest of the number
23945 	 */
23946 	service4: function(number, currentChar, fields, regionSettings) {
23947 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('service4'), number, currentChar, fields, regionSettings, false);
23948 	},
23949 	/**
23950 	 * @private
23951 	 * @param {string} number phone number
23952 	 * @param {number} currentChar currentChar to be parsed
23953 	 * @param {Object} fields the fields that have been extracted so far
23954 	 * @param {Object} regionSettings settings used to parse the rest of the number
23955 	 */
23956 	cic2: function(number, currentChar, fields, regionSettings) {
23957 		return this.processField('cic', regionSettings.plan.getFieldLength('cic2'), number, currentChar, fields, regionSettings);
23958 	},
23959 	/**
23960 	 * @private
23961 	 * @param {string} number phone number
23962 	 * @param {number} currentChar currentChar to be parsed
23963 	 * @param {Object} fields the fields that have been extracted so far
23964 	 * @param {Object} regionSettings settings used to parse the rest of the number
23965 	 */
23966 	cic3: function(number, currentChar, fields, regionSettings) {
23967 		return this.processField('cic', regionSettings.plan.getFieldLength('cic3'), number, currentChar, fields, regionSettings);
23968 	},
23969 	/**
23970 	 * @private
23971 	 * @param {string} number phone number
23972 	 * @param {number} currentChar currentChar to be parsed
23973 	 * @param {Object} fields the fields that have been extracted so far
23974 	 * @param {Object} regionSettings settings used to parse the rest of the number
23975 	 */
23976 	start: function(number, currentChar, fields, regionSettings) {
23977 		// don't do anything except transition to the next state
23978 		return {
23979 			number: number
23980 		};
23981 	},
23982 	/**
23983 	 * @private
23984 	 * @param {string} number phone number
23985 	 * @param {number} currentChar currentChar to be parsed
23986 	 * @param {Object} fields the fields that have been extracted so far
23987 	 * @param {Object} regionSettings settings used to parse the rest of the number
23988 	 */
23989 	local: function(number, currentChar, fields, regionSettings) {
23990 		// in open dialling plans, we can tell that this number is a local subscriber number because it
23991 		// starts with a digit that indicates as such
23992 		this.processSubscriberNumber(number, fields, regionSettings);
23993 		return {
23994 			number: ""
23995 		};
23996 	}
23997 };
23998 
23999 // context-sensitive handler
24000 /**
24001  * @class
24002  * @private
24003  * @constructor
24004  */
24005 ilib.CSStateHandler = function () {
24006 	return this;
24007 };
24008 
24009 ilib.CSStateHandler.prototype = new ilib.StateHandler();
24010 ilib.CSStateHandler.prototype.special = function (number, currentChar, fields, regionSettings) {
24011 	var ret;
24012 	
24013 	// found a special area code that is both a node and a leaf. In
24014 	// this state, we have found the leaf, so chop off the end 
24015 	// character to make it a leaf.
24016 	if (number.charAt(0) === "0") {
24017 		fields.trunkAccess = number.charAt(0);
24018 		fields.areaCode = number.substring(1, currentChar);
24019 	} else {
24020 		fields.areaCode = number.substring(0, currentChar);
24021 	}
24022 	this.processSubscriberNumber(number.substring(currentChar), fields, regionSettings);
24023 	
24024 	ret = {
24025 		number: ""
24026 	};
24027 	
24028 	return ret;
24029 };
24030 
24031 /**
24032  * @class
24033  * @private
24034  * @constructor
24035  */
24036 ilib.USStateHandler = function () {
24037 	return this;
24038 };
24039 
24040 ilib.USStateHandler.prototype = new ilib.StateHandler();
24041 ilib.USStateHandler.prototype.vsc = function (number, currentChar, fields, regionSettings) {
24042 	var ret;
24043 
24044 	// found a VSC code (ie. a "star code")
24045 	fields.vsc = number;
24046 
24047 	// treat the rest of the number as if it were a completely new number
24048 	ret = {
24049 		number: ""
24050 	};
24051 
24052 	return ret;
24053 };
24054 
24055 /**
24056  * @protected
24057  * @static
24058  */
24059 ilib._handlerFactory = function (locale, plan) {
24060 	if (plan.getContextFree() !== undefined && typeof(plan.getContextFree()) === 'boolean' && plan.getContextFree() === false) {
24061 		return new ilib.CSStateHandler();
24062 	}
24063 	var region = (locale && locale.getRegion()) || "ZZ";
24064 	switch (region) {
24065 	case 'US':
24066 		return new ilib.USStateHandler();
24067 		break;
24068 	default:
24069 		return new ilib.StateHandler();
24070 	}
24071 };
24072 /*
24073  * phonenum.js - Represent a phone number.
24074  * 
24075  * Copyright © 2014, JEDLSoft
24076  *
24077  * Licensed under the Apache License, Version 2.0 (the "License");
24078  * you may not use this file except in compliance with the License.
24079  * You may obtain a copy of the License at
24080  *
24081  *     http://www.apache.org/licenses/LICENSE-2.0
24082  *
24083  * Unless required by applicable law or agreed to in writing, software
24084  * distributed under the License is distributed on an "AS IS" BASIS,
24085  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24086  *
24087  * See the License for the specific language governing permissions and
24088  * limitations under the License.
24089  */
24090 
24091 /*
24092 !depends 
24093 ilibglobal.js
24094 locale.js 
24095 localeinfo.js
24096 phone/numplan.js
24097 phone/phoneloc.js
24098 phone/handler.js
24099 */
24100 
24101 // !data states idd mnc
24102 
24103 /**
24104  * @class
24105  * Create a new phone number instance that parses the phone number parameter for its 
24106  * constituent parts, and store them as separate fields in the returned object.
24107  * 
24108  * The options object may include any of these properties:
24109  * 
24110  * <ul>
24111  * <li><i>locale</i> The locale with which to parse the number. This gives a clue as to which
24112  * numbering plan to use.
24113  * <li><i>mcc</i> The mobile carrier code (MCC) associated with the carrier that the phone is 
24114  * currently connected to, if known. This also can give a clue as to which numbering plan to
24115  * use
24116  * <li>onLoad - a callback function to call when this instance is fully 
24117  * loaded. When the onLoad option is given, this class will attempt to
24118  * load any missing locale data using the ilib loader callback.
24119  * When the constructor is done (even if the data is already preassembled), the 
24120  * onLoad function is called with the current instance as a parameter, so this
24121  * callback can be used with preassembled or dynamic loading or a mix of the two.
24122  * <li>sync - tell whether to load any missing locale data synchronously or 
24123  * asynchronously. If this option is given as "false", then the "onLoad"
24124  * callback must be given, as the instance returned from this constructor will
24125  * not be usable for a while.
24126  * <li><i>loadParams</i> - an object containing parameters to pass to the 
24127  * loader callback function when locale data is missing. The parameters are not
24128  * interpretted or modified in any way. They are simply passed along. The object 
24129  * may contain any property/value pairs as long as the calling code is in
24130  * agreement with the loader callback function as to what those parameters mean.
24131  * </ul>
24132  * 
24133  * This function is locale-sensitive, and will assume any number passed to it is
24134  * appropriate for the given locale. If the MCC is given, this method will assume
24135  * that numbers without an explicit country code have been dialled within the country
24136  * given by the MCC. This affects how things like area codes are parsed. If the MCC
24137  * is not given, this method will use the given locale to determine the country
24138  * code. If the locale is not explicitly given either, then this function uses the 
24139  * region of current locale as the default.<p>
24140  * 
24141  * The input number may contain any formatting characters for the given locale. Each 
24142  * field that is returned in the json object is a simple string of digits with
24143  * all formatting and whitespace characters removed.<p>
24144  * 
24145  * The number is decomposed into its parts, regardless if the number
24146  * contains formatting characters. If a particular part cannot be extracted from given 
24147  * number, the field will not be returned as a field in the object. If no fields can be
24148  * extracted from the number at all, then all digits found in the string will be 
24149  * returned in the subscriberNumber field. If the number parameter contains no 
24150  * digits, an empty object is returned.<p>
24151  * 
24152  * This instance can contain any of the following fields after parsing is done:
24153  * 
24154  * <ul>
24155  * <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
24156  * <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
24157  * <li>countryCode - if this number is an international direct dial number, this is the country code
24158  * <li>cic - for "dial-around" services (access to other carriers), this is the prefix used as the carrier identification code
24159  * <li>emergency - an emergency services number
24160  * <li>mobilePrefix - prefix that introduces a mobile phone number
24161  * <li>trunkAccess - trunk access code (long-distance access)
24162  * <li>serviceCode - like a geographic area code, but it is a required prefix for various services
24163  * <li>areaCode - geographic area codes
24164  * <li>subscriberNumber - the unique number of the person or company that pays for this phone line
24165  * <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.
24166  * <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
24167  * </ul>
24168  * 
24169  * The following rules determine how the number is parsed:
24170  * 
24171  * <ol>
24172  * <li>If the number starts with a character that is alphabetic instead of numeric, do
24173  * not parse the number at all. There is a good chance that it is not really a phone number.
24174  * In this case, an empty instance will be returned.
24175  * <li>If the phone number uses the plus notation or explicitly uses the international direct
24176  * dialing prefix for the given locale, then the country code is identified in 
24177  * the number. The rules of given locale are used to parse the IDD prefix, and then the rules
24178  * of the country in the prefix are used to parse the rest of the number.
24179  * <li>If a country code is provided as an argument to the function call, use that country's
24180  * parsing rules for the number. This is intended for programs like a Contacts application that 
24181  * know what the country is of the person that owns the phone number and can pass that on as 
24182  * a hint.
24183  * <li>If the appropriate locale cannot be easily determined, default to using the rules 
24184  * for the current user's region.
24185  * </ol>
24186  * 
24187  * Example: parsing the number "+49 02101345345-78" will give the following properties in the
24188  * resulting phone number instance:
24189  * 
24190  * <pre>
24191  *      {
24192  *        iddPrefix: "+",
24193  *        countryCode: "49",
24194  *        areaCode: "02101",
24195  *        subscriberNumber: "345345",
24196  *        extension: "78"
24197  *      }
24198  * </pre>
24199  *  
24200  * Note that in this example, because international direct dialing is explicitly used 
24201  * in the number, the part of this number after the IDD prefix and country code will be 
24202  * parsed exactly the same way in all locales with German rules (country code 49).
24203  *  
24204  * Regions currently supported are:
24205  *  
24206  * <ul>
24207  * <li>NANP (North American Numbering Plan) countries - USA, Canada, Bermuda, various Caribbean nations
24208  * <li>UK
24209  * <li>Republic of Ireland
24210  * <li>Germany
24211  * <li>France
24212  * <li>Spain
24213  * <li>Italy
24214  * <li>Mexico
24215  * <li>India
24216  * <li>People's Republic of China
24217  * <li>Netherlands
24218  * <li>Belgium
24219  * <li>Luxembourg
24220  * <li>Australia
24221  * <li>New Zealand
24222  * <li>Singapore
24223  * <li>Korea
24224  * <li>Japan
24225  * <li>Russia
24226  * <li>Brazil
24227  * </ul>
24228  * 
24229  * @constructor
24230  * @param {!string|ilib.PhoneNumber} number A free-form phone number to be parsed, or another phone
24231  * number instance to copy
24232  * @param {Object=} options options that guide the parser in parsing the number
24233  */
24234 ilib.PhoneNumber = function(number, options) {
24235 	var stateData,
24236 		regionSettings;
24237 
24238 	this.sync = true;
24239 	this.loadParams = {};
24240 	
24241 	if (!number || (typeof number === "string" && number.length === 0)) {
24242 		return this;
24243 	}
24244 
24245 	if (options) {
24246 		if (typeof(options.sync) === 'boolean') {
24247 			this.sync = options.sync;
24248 		}
24249 
24250 		if (options.loadParams) {
24251 			this.loadParams = options.loadParams;
24252 		}
24253 
24254 		if (typeof(options.onLoad) === 'function') {
24255 			/** 
24256 			 * @private
24257 			 * @type {function(ilib.PhoneNumber)} 
24258 			 */
24259 			this.onLoad = options.onLoad;
24260 		}
24261 	}
24262 
24263 	if (typeof number === "object") {
24264 		/**
24265 		 * The vertical service code. These are codes that typically
24266 		 * start with a star or hash, like "*69" for "dial back the 
24267 		 * last number that called me".
24268 		 * @type {string|undefined} 
24269 		 */
24270 		this.vsc = number.vsc;
24271 
24272 		/**
24273 		 * The international direct dialing prefix. This is always
24274 		 * followed by the country code. 
24275 		 * @type {string} 
24276 		 */
24277 		this.iddPrefix = number.iddPrefix;
24278 		
24279 		/**
24280 		 * The unique IDD country code for the country where the
24281 		 * phone number is serviced. 
24282 		 * @type {string|undefined} 
24283 		 */
24284 		this.countryCode = number.countryCode;
24285 		
24286 		/**
24287 		 * The digits required to access the trunk. 
24288 		 * @type {string|undefined} 
24289 		 */
24290 		this.trunkAccess = number.trunkAccess;
24291 		
24292 		/**
24293 		 * The carrier identification code used to identify 
24294 		 * alternate long distance or international carriers. 
24295 		 * @type {string|undefined} 
24296 		 */
24297 		this.cic = number.cic;
24298 		
24299 		/**
24300 		 * Identifies an emergency number that is typically
24301 		 * short, such as "911" in North America or "112" in
24302 		 * many other places in the world. 
24303 		 * @type {string|undefined} 
24304 		 */
24305 		this.emergency = number.emergency;
24306 		
24307 		/**
24308 		 * The prefix of the subscriber number that indicates
24309 		 * that this is the number of a mobile phone. 
24310 		 * @type {string|undefined} 
24311 		 */
24312 		this.mobilePrefix = number.mobilePrefix;
24313 		
24314 		/**
24315 		 * The prefix that identifies this number as commercial
24316 		 * service number. 
24317 		 * @type {string|undefined} 
24318 		 */
24319 		this.serviceCode = number.serviceCode;
24320 		
24321 		/**
24322 		 * The area code prefix of a land line number. 
24323 		 * @type {string|undefined} 
24324 		 */
24325 		this.areaCode = number.areaCode;
24326 		
24327 		/**
24328 		 * The unique number associated with the subscriber
24329 		 * of this phone. 
24330 		 * @type {string|undefined} 
24331 		 */
24332 		this.subscriberNumber = number.subscriberNumber;
24333 		
24334 		/**
24335 		 * The direct dial extension number. 
24336 		 * @type {string|undefined} 
24337 		 */
24338 		this.extension = number.extension;
24339 		
24340 		/**
24341 		 * @private
24342 		 * @type {boolean} 
24343 		 */
24344 		this.invalid = number.invalid;
24345 
24346 		if (number.plan && number.locale) {
24347 			/** 
24348 			 * @private
24349 			 * @type {ilib.NumPlan} 
24350 			 */
24351 			this.plan = number.plan;
24352 			
24353 			/** 
24354 			 * @private
24355 			 * @type {ilib.Locale.PhoneLoc} 
24356 			 */
24357 			this.locale = number.locale;
24358 	
24359 			/** 
24360 			 * @private
24361 			 * @type {ilib.NumPlan} 
24362 			 */
24363 			this.destinationPlan = number.destinationPlan;
24364 			
24365 			/** 
24366 			 * @private
24367 			 * @type {ilib.Locale.PhoneLoc} 
24368 			 */
24369 			this.destinationLocale = number.destinationLocale;
24370 	
24371 			if (options && typeof(options.onLoad) === 'function') {
24372 				options.onLoad(this);
24373 			}
24374 			return;
24375 		}
24376 	}
24377 
24378 	new ilib.Locale.PhoneLoc({
24379 		locale: options && options.locale,
24380 		mcc: options && options.mcc,
24381 		sync: this.sync,
24382 		loadParams: this.loadParams,
24383 		onLoad: ilib.bind(this, function(loc) {
24384 			this.locale = this.destinationLocale = loc;
24385 			new ilib.NumPlan({
24386 				locale: this.locale,
24387 				sync: this.sync,
24388 				loadParms: this.loadParams,
24389 				onLoad: ilib.bind(this, function (plan) {
24390 					this.plan = this.destinationPlan = plan;
24391 			
24392 					if (typeof number === "object") {
24393 						// the copy constructor code above did not find the locale 
24394 						// or plan before, but now they are loaded, so we can return 
24395 						// already without going further
24396 						return;
24397 					}
24398 					ilib.loadData({
24399 						name: "states.json",
24400 						object: ilib.PhoneNumber,
24401 						locale: this.locale,
24402 						sync: this.sync,
24403 						loadParams: ilib.merge(this.loadParams, {
24404 							returnOne: true
24405 						}),
24406 						callback: ilib.bind(this, function (stdata) {
24407 							if (!stdata) {
24408 								stdata = ilib.PhoneNumber._defaultStates;
24409 							}
24410 		
24411 							stateData = stdata;
24412 
24413 							regionSettings = {
24414 								stateData: stateData,
24415 								plan: plan,
24416 								handler: ilib._handlerFactory(this.locale, plan)
24417 							};
24418 							
24419 							// use ^ to indicate the beginning of the number, because certain things only match at the beginning
24420 							number = "^" + number.replace(/\^/g, '');
24421 							number = ilib.PhoneNumber._stripFormatting(number);
24422 
24423 							this._parseNumber(number, regionSettings, options);
24424 						})
24425 					});
24426 				})
24427 			});
24428 		})
24429 	});
24430 };
24431 
24432 /**
24433  * Parse an International Mobile Subscriber Identity (IMSI) number into its 3 constituent parts:
24434  * 
24435  * <ol>
24436  * <li>mcc - Mobile Country Code, which identifies the country where the phone is currently receiving 
24437  * service.
24438  * <li>mnc - Mobile Network Code, which identifies the carrier which is currently providing service to the phone 
24439  * <li>msin - Mobile Subscription Identifier Number. This is a unique number identifying the mobile phone on 
24440  * the network, which usually maps to an account/subscriber in the carrier's database.
24441  * </ol>
24442  * 
24443  * Because this function may need to load data to identify the above parts, you can pass an options
24444  * object that controls how the data is loaded. The options may contain any of the following properties:
24445  *
24446  * <ul>
24447  * <li>onLoad - a callback function to call when the parsing is done. When the onLoad option is given, 
24448  * this method will attempt to load the locale data using the ilib loader callback. When it is done
24449  * (even if the data is already preassembled), the onLoad function is called with the parsing results
24450  * as a parameter, so this callback can be used with preassembled or dynamic, synchronous or 
24451  * asynchronous loading or a mix of the above.
24452  * <li>sync - tell whether to load any missing locale data synchronously or asynchronously. If this 
24453  * option is given as "false", then the "onLoad" callback must be given, as the results returned from 
24454  * this constructor will not be usable for a while.
24455  * <li><i>loadParams</i> - an object containing parameters to pass to the loader callback function 
24456  * when locale data is missing. The parameters are not interpretted or modified in any way. They are 
24457  * simply passed along. The object may contain any property/value pairs as long as the calling code is in
24458  * agreement with the loader callback function as to what those parameters mean.
24459  * </ul>
24460  *
24461  * @static
24462  * @param {string} imsi IMSI number to parse
24463  * @param {Object} options options controlling the loading of the locale data
24464  * @return {{mcc:string,mnc:string,msin:string}|undefined} components of the IMSI number, when the locale data
24465  * is loaded synchronously, or undefined if asynchronous
24466  */
24467 ilib.PhoneNumber.parseImsi = function(imsi, options) {
24468 	var sync = true,
24469 		loadParams = {},
24470 		fields = {};
24471 	
24472 	if (!imsi) {
24473 		return undefined;
24474 	}
24475 
24476 	if (options) {
24477 		if (typeof(options.sync) !== 'undefined') {
24478 			sync = (options.sync == true);
24479 		}
24480 		
24481 		if (options.loadParams) {
24482 			loadParams = options.loadParams;
24483 		}
24484 	}	
24485 
24486 	if (ilib.data.mnc) {
24487 		fields = ilib.PhoneNumber._parseImsi(ilib.data.mnc, imsi);
24488 		
24489 		if (options && typeof(options.onLoad) === 'function') {
24490 			options.onLoad(fields);
24491 		}
24492 	} else {
24493 		ilib.loadData({
24494 			name: "mnc.json", 
24495 			object: ilib.PhoneNumber, 
24496 			nonlocale: true, 
24497 			sync: sync, 
24498 			loadParams: loadParams, 
24499 			callback: ilib.bind(this, function(data) {
24500 				ilib.data.mnc = data;
24501 				fields = ilib.PhoneNumber._parseImsi(data, imsi);
24502 				
24503 				if (options && typeof(options.onLoad) === 'function') {
24504 					options.onLoad(fields);
24505 				}
24506 			})
24507 		});
24508 	}
24509 	return fields;
24510 };
24511 
24512 
24513 /**
24514  * @static
24515  * @protected
24516  */
24517 ilib.PhoneNumber._parseImsi = function(data, imsi) {
24518 	var ch, 
24519 		i,
24520 		currentState, 
24521 		end, 
24522 		handlerMethod,
24523 		state = 0,
24524 		newState,
24525 		fields = {},
24526 		lastLeaf,
24527 		consumed = 0;
24528 	
24529 	currentState = data;
24530 	if (!currentState) {
24531 		// can't parse anything
24532 		return undefined;
24533 	}
24534 	
24535 	i = 0;
24536 	while (i < imsi.length) {
24537 		ch = ilib.PhoneNumber._getCharacterCode(imsi.charAt(i));
24538 		// console.info("parsing char " + imsi.charAt(i) + " code: " + ch);
24539 		if (ch >= 0) {
24540 			newState = currentState.s && currentState.s[ch];
24541 			
24542 			if (typeof(newState) === 'object') {
24543 				if (typeof(newState.l) !== 'undefined') {
24544 					// save for latter if needed
24545 					lastLeaf = newState;
24546 					consumed = i;
24547 				}
24548 				// console.info("recognized digit " + ch + " continuing...");
24549 				// recognized digit, so continue parsing
24550 				currentState = newState;
24551 				i++;
24552 			} else {
24553 				if ((typeof(newState) === 'undefined' || newState === 0 ||
24554 					(typeof(newState) === 'object' && typeof(newState.l) === 'undefined')) &&
24555 					 lastLeaf) {
24556 					// this is possibly a look-ahead and it didn't work... 
24557 					// so fall back to the last leaf and use that as the
24558 					// final state
24559 					newState = lastLeaf;
24560 					i = consumed;
24561 				}
24562 				
24563 				if ((typeof(newState) === 'number' && newState) ||
24564 					(typeof(newState) === 'object' && typeof(newState.l) !== 'undefined')) {
24565 					// final state
24566 					var stateNumber = typeof(newState) === 'number' ? newState : newState.l;
24567 					handlerMethod = ilib.PhoneNumber._states[stateNumber];
24568 
24569 					// console.info("reached final state " + newState + " handler method is " + handlerMethod + " and i is " + i);
24570 	
24571 					// deal with syntactic ambiguity by using the "special" end state instead of "area"
24572 					if ( handlerMethod === "area" ) {
24573 						end = i+1;
24574 					} else {
24575 						// unrecognized imsi, so just assume the mnc is 3 digits
24576 						end = 6;
24577 					}
24578 					
24579 					fields.mcc = imsi.substring(0,3);
24580 					fields.mnc = imsi.substring(3,end);
24581 					fields.msin = imsi.substring(end);
24582 	
24583 					return fields;
24584 				} else {
24585 					// parse error
24586 					if (imsi.length >= 6) {
24587 						fields.mcc = imsi.substring(0,3);
24588 						fields.mnc = imsi.substring(3,6);
24589 						fields.msin = imsi.substring(6);
24590 					}
24591 					return fields;
24592 				}
24593 			}
24594 		} else if (ch === -1) {
24595 			// non-transition character, continue parsing in the same state
24596 			i++;
24597 		} else {
24598 			// should not happen
24599 			// console.info("skipping character " + ch);
24600 			// not a digit, plus, pound, or star, so this is probably a formatting char. Skip it.
24601 			i++;
24602 		}
24603 	}
24604 		
24605 	if (i >= imsi.length && imsi.length >= 6) {
24606 		// we reached the end of the imsi, but did not finish recognizing anything. 
24607 		// Default to last resort and assume 3 digit mnc
24608 		fields.mcc = imsi.substring(0,3);
24609 		fields.mnc = imsi.substring(3,6);
24610 		fields.msin = imsi.substring(6);
24611 	} else {
24612 		// unknown or not enough characters for a real imsi 
24613 		fields = undefined;
24614 	}
24615 		
24616 	// console.info("Globalization.Phone.parseImsi: final result is: " + JSON.stringify(fields));
24617 	return fields;
24618 };
24619 
24620 /**
24621  * @static
24622  * @private
24623  */
24624 ilib.PhoneNumber._stripFormatting = function(str) {
24625 	var ret = "";
24626 	var i;
24627 
24628 	for (i = 0; i < str.length; i++) {
24629 		if (ilib.PhoneNumber._getCharacterCode(str.charAt(i)) >= -1) {
24630 			ret += str.charAt(i);
24631 		}
24632 	}
24633 	return ret;
24634 };
24635 
24636 /**
24637  * @static
24638  * @protected
24639  */
24640 ilib.PhoneNumber._getCharacterCode = function(ch) {
24641 	if (ch >= '0' && ch <= '9') {
24642 			return ch - '0';
24643 		}
24644 	switch (ch) {
24645 	case '+':
24646 		return 10;
24647 	case '*':
24648 		return 11;
24649 	case '#':
24650 		return 12;
24651 	case '^':
24652 		return 13;
24653 	case 'p':		// pause chars
24654 	case 'P':
24655 	case 't':
24656 	case 'T':
24657 	case 'w':
24658 	case 'W':
24659 		return -1;
24660 	case 'x':
24661 	case 'X':
24662 	case ',':
24663 	case ';':		// extension char
24664 		return -1;
24665 	}
24666 	return -2;
24667 };
24668 
24669 /**
24670  * @private
24671  */
24672 ilib.PhoneNumber._states = [
24673 	"none",
24674 	"unknown",
24675 	"plus",
24676 	"idd",
24677 	"cic",
24678 	"service",
24679 	"cell",
24680 	"area",
24681 	"vsc",
24682 	"country",
24683 	"personal",
24684 	"special",
24685 	"trunk",
24686 	"premium",
24687 	"emergency",
24688 	"service2",
24689 	"service3",
24690 	"service4",
24691 	"cic2",
24692 	"cic3",
24693 	"start",
24694 	"local"
24695 ];
24696 
24697 /**
24698  * @private
24699  */
24700 ilib.PhoneNumber._fieldOrder = [
24701 	"vsc",
24702 	"iddPrefix",
24703 	"countryCode",
24704 	"trunkAccess",
24705 	"cic",
24706 	"emergency",
24707 	"mobilePrefix",
24708 	"serviceCode",
24709 	"areaCode",
24710 	"subscriberNumber",
24711 	"extension"
24712 ];
24713 
24714 ilib.PhoneNumber._defaultStates = {
24715 	"s": [
24716         0,
24717 		21,  // 1 -> local
24718         21,  // 2 -> local
24719         21,  // 3 -> local
24720         21,  // 4 -> local
24721         21,  // 5 -> local
24722         21,  // 6 -> local
24723         21,  // 7 -> local
24724         21,  // 8 -> local
24725         21,  // 9 -> local
24726         0,0,0,
24727 	    { // ^
24728 	    	"s": [
24729 				{ // ^0
24730 					"s": [3], // ^00 -> idd
24731 					"l": 12   // ^0  -> trunk
24732 				},
24733 				21,  // ^1 -> local
24734 	            21,  // ^2 -> local
24735 	            21,  // ^3 -> local
24736 	            21,  // ^4 -> local
24737 	            21,  // ^5 -> local
24738 	            21,  // ^6 -> local
24739 	            21,  // ^7 -> local
24740 	            21,  // ^8 -> local
24741 	            21,  // ^9 -> local
24742 	            2    // ^+ -> plus
24743 	        ]
24744 	    }
24745 	]
24746 };
24747 
24748 ilib.PhoneNumber.prototype = {
24749 	/**
24750 	 * @protected
24751 	 * @param {string} number
24752 	 * @param {Object} regionData
24753 	 * @param {Object} options
24754 	 * @param {string} countryCode
24755 	 */
24756 	_parseOtherCountry: function(number, regionData, options, countryCode) {
24757 		new ilib.Locale.PhoneLoc({
24758 			locale: this.locale,
24759 			countryCode: countryCode,
24760 			sync: this.sync,
24761 			loadParms: this.loadParams,
24762 			onLoad: ilib.bind(this, function (loc) {
24763 				/*
24764 				 * this.locale is the locale where this number is being parsed,
24765 				 * and is used to parse the IDD prefix, if any, and this.destinationLocale is 
24766 				 * the locale of the rest of this number after the IDD prefix.
24767 				 */
24768 				/** @type {ilib.Locale.PhoneLoc} */
24769 				this.destinationLocale = loc;
24770 
24771 				ilib.loadData({
24772 					name: "states.json",
24773 					object: ilib.PhoneNumber,
24774 					locale: this.destinationLocale,
24775 					sync: this.sync,
24776 					loadParams: ilib.merge(this.loadParams, {
24777 						returnOne: true
24778 					}),
24779 					callback: ilib.bind(this, function (stateData) {
24780 						if (!stateData) {
24781 							stateData = ilib.PhoneNumber._defaultStates;
24782 						}
24783 						
24784 						new ilib.NumPlan({
24785 							locale: this.destinationLocale,
24786 							sync: this.sync,
24787 							loadParms: this.loadParams,
24788 							onLoad: ilib.bind(this, function (plan) {
24789 								/*
24790 								 * this.plan is the plan where this number is being parsed,
24791 								 * and is used to parse the IDD prefix, if any, and this.destinationPlan is 
24792 								 * the plan of the rest of this number after the IDD prefix in the 
24793 								 * destination locale.
24794 								 */
24795 								/** @type {ilib.NumPlan} */
24796 								this.destinationPlan = plan;
24797 
24798 								var regionSettings = {
24799 									stateData: stateData,
24800 									plan: plan,
24801 									handler: ilib._handlerFactory(this.destinationLocale, plan)
24802 								};
24803 								
24804 								// for plans that do not skip the trunk code when dialing from
24805 								// abroad, we need to treat the number from here on in as if it 
24806 								// were parsing a local number from scratch. That way, the parser
24807 								// does not get confused between parts of the number at the
24808 								// beginning of the number, and parts in the middle.
24809 								if (!plan.getSkipTrunk()) {
24810 									number = '^' + number;
24811 								}
24812 									
24813 								// recursively call the parser with the new states data
24814 								// to finish the parsing
24815 								this._parseNumber(number, regionSettings, options);
24816 							})
24817 						});
24818 					})
24819 				});
24820 			})
24821 		});
24822 	},
24823 	
24824 	/**
24825 	 * @protected
24826 	 * @param {string} number
24827 	 * @param {Object} regionData
24828 	 * @param {Object} options
24829 	 */
24830 	_parseNumber: function(number, regionData, options) {
24831 		var i, ch,
24832 			regionSettings,
24833 			newState,
24834 			dot,
24835 			handlerMethod,
24836 			result,
24837 			currentState = regionData.stateData,
24838 			lastLeaf = undefined,
24839 			consumed = 0;
24840 
24841 		regionSettings = regionData;
24842 		dot = 14; // special transition which matches all characters. See AreaCodeTableMaker.java
24843 
24844 		i = 0;
24845 		while (i < number.length) {
24846 			ch = ilib.PhoneNumber._getCharacterCode(number.charAt(i));
24847 			if (ch >= 0) {
24848 				// newState = stateData.states[state][ch];
24849 				newState = currentState.s && currentState.s[ch];
24850 				
24851 				if (!newState && currentState.s && currentState.s[dot]) {
24852 					newState = currentState.s[dot];
24853 				}
24854 				
24855 				if (typeof(newState) === 'object' && i+1 < number.length) {
24856 					if (typeof(newState.l) !== 'undefined') {
24857 						// this is a leaf node, so save that for later if needed
24858 						lastLeaf = newState;
24859 						consumed = i;
24860 					}
24861 					// console.info("recognized digit " + ch + " continuing...");
24862 					// recognized digit, so continue parsing
24863 					currentState = newState;
24864 					i++;
24865 				} else {
24866 					if ((typeof(newState) === 'undefined' || newState === 0 ||
24867 						(typeof(newState) === 'object' && typeof(newState.l) === 'undefined')) &&
24868 						 lastLeaf) {
24869 						// this is possibly a look-ahead and it didn't work... 
24870 						// so fall back to the last leaf and use that as the
24871 						// final state
24872 						newState = lastLeaf;
24873 						i = consumed;
24874 						consumed = 0;
24875 						lastLeaf = undefined;
24876 					}
24877 					
24878 					if ((typeof(newState) === 'number' && newState) ||
24879 						(typeof(newState) === 'object' && typeof(newState.l) !== 'undefined')) {
24880 						// final state
24881 						var stateNumber = typeof(newState) === 'number' ? newState : newState.l;
24882 						handlerMethod = ilib.PhoneNumber._states[stateNumber];
24883 						
24884 						if (number.charAt(0) === '^') {
24885 							result = regionSettings.handler[handlerMethod](number.slice(1), i-1, this, regionSettings);
24886 						} else {
24887 							result = regionSettings.handler[handlerMethod](number, i, this, regionSettings);
24888 						}
24889 		
24890 						// reparse whatever is left
24891 						number = result.number;
24892 						i = consumed = 0;
24893 						lastLeaf = undefined;
24894 						
24895 						//console.log("reparsing with new number: " +  number);
24896 						currentState = regionSettings.stateData;
24897 						// if the handler requested a special sub-table, use it for this round of parsing,
24898 						// otherwise, set it back to the regular table to continue parsing
24899 	
24900 						if (result.countryCode !== undefined) {
24901 							this._parseOtherCountry(number, regionData, options, result.countryCode);
24902 							// don't process any further -- let the work be done in the onLoad callbacks
24903 							return;
24904 						} else if (result.table !== undefined) {
24905 							ilib.loadData({
24906 								name: result.table + ".json",
24907 								object: ilib.PhoneNumber,
24908 								nonlocale: true,
24909 								sync: this.sync,
24910 								loadParams: this.loadParams,
24911 								callback: ilib.bind(this, function (data) {
24912 									if (!data) {
24913 										data = ilib.PhoneNumber._defaultStates;
24914 									}
24915 	
24916 									regionSettings = {
24917 										stateData: data,
24918 										plan: regionSettings.plan,
24919 										handler: regionSettings.handler
24920 									};
24921 									
24922 									// recursively call the parser with the new states data
24923 									// to finish the parsing
24924 									this._parseNumber(number, regionSettings, options);
24925 								})
24926 							});
24927 							// don't process any further -- let the work be done in the onLoad callbacks
24928 							return;
24929 						} else if (result.skipTrunk !== undefined) {
24930 							ch = ilib.PhoneNumber._getCharacterCode(regionSettings.plan.getTrunkCode());
24931 							currentState = currentState.s && currentState.s[ch];
24932 						}
24933 					} else {
24934 						handlerMethod = (typeof(newState) === 'number') ? "none" : "local";
24935 						// failed parse. Either no last leaf to fall back to, or there was an explicit
24936 						// zero in the table. Put everything else in the subscriberNumber field as the
24937 						// default place
24938 						if (number.charAt(0) === '^') {
24939 							result = regionSettings.handler[handlerMethod](number.slice(1), i-1, this, regionSettings);
24940 						} else {
24941 							result = regionSettings.handler[handlerMethod](number, i, this, regionSettings);
24942 						}
24943 						break;
24944 					}
24945 				}
24946 			} else if (ch === -1) {
24947 				// non-transition character, continue parsing in the same state
24948 				i++;
24949 			} else {
24950 				// should not happen
24951 				// console.info("skipping character " + ch);
24952 				// not a digit, plus, pound, or star, so this is probably a formatting char. Skip it.
24953 				i++;
24954 			}
24955 		}
24956 		if (i >= number.length && currentState !== regionData.stateData) {
24957 			handlerMethod = (typeof(currentState.l) === 'undefined' || currentState === 0) ? "none" : "local";
24958 			// we reached the end of the phone number, but did not finish recognizing anything. 
24959 			// Default to last resort and put everything that is left into the subscriber number
24960 			//console.log("Reached end of number before parsing was complete. Using handler for method none.")
24961 			if (number.charAt(0) === '^') {
24962 				result = regionSettings.handler[handlerMethod](number.slice(1), i-1, this, regionSettings);
24963 			} else {
24964 				result = regionSettings.handler[handlerMethod](number, i, this, regionSettings);
24965 			}
24966 		}
24967 
24968 		// let the caller know we are done parsing
24969 		if (this.onLoad) {
24970 			this.onLoad(this);
24971 		}
24972 	},
24973 	/**
24974 	 * @protected
24975 	 */
24976 	_getPrefix: function() {
24977 		return this.areaCode || this.serviceCode || this.mobilePrefix || "";
24978 	},
24979 	
24980 	/**
24981 	 * @protected
24982 	 */
24983 	_hasPrefix: function() {
24984 		return (this._getPrefix() !== "");
24985 	},
24986 	
24987 	/**
24988 	 * Exclusive or -- return true, if one is defined and the other isn't
24989 	 * @protected
24990 	 */
24991 	_xor : function(left, right) {
24992 		if ((left === undefined && right === undefined ) || (left !== undefined && right !== undefined)) {
24993 			return false;
24994 		} else {
24995 			return true;
24996 		}
24997 	},
24998 	
24999 	/**
25000 	 * return a version of the phone number that contains only the dialable digits in the correct order 
25001 	 * @protected
25002 	 */
25003 	_join: function () {
25004 		var fieldName, formatted = "";
25005 		
25006 		try {
25007 			for (var field in ilib.PhoneNumber._fieldOrder) {
25008 				if (typeof field === 'string' && typeof ilib.PhoneNumber._fieldOrder[field] === 'string') {
25009 					fieldName = ilib.PhoneNumber._fieldOrder[field];
25010 					// console.info("normalize: formatting field " + fieldName);
25011 					if (this[fieldName] !== undefined) {
25012 						formatted += this[fieldName];
25013 					}
25014 				}
25015 			}
25016 		} catch ( e ) {
25017 			//console.warn("caught exception in _join: " + e);
25018 			throw e;
25019 		}
25020 		return formatted;
25021 	},
25022 
25023 	/**
25024 	 * This routine will compare the two phone numbers in an locale-sensitive
25025 	 * manner to see if they possibly reference the same phone number.<p>
25026 	 * 
25027 	 * In many places,
25028 	 * there are multiple ways to reach the same phone number. In North America for 
25029 	 * example, you might have a number with the trunk access code of "1" and another
25030 	 * without, and they reference the exact same phone number. This is considered a
25031 	 * strong match. For a different pair of numbers, one may be a local number and
25032 	 * the other a full phone number with area code, which may reference the same 
25033 	 * phone number if the local number happens to be located in that area code. 
25034 	 * However, you cannot say for sure if it is in that area code, so it will 
25035 	 * be considered a somewhat weaker match.<p>
25036 	 *  
25037 	 * Similarly, in other countries, there are sometimes different ways of 
25038 	 * reaching the same destination, and the way that numbers
25039 	 * match depends on the locale.<p>
25040 	 * 
25041 	 * The various phone number fields are handled differently for matches. There
25042 	 * are various fields that do not need to match at all. For example, you may
25043 	 * type equally enter "00" or "+" into your phone to start international direct
25044 	 * dialling, so the iddPrefix field does not need to match at all.<p> 
25045 	 * 
25046 	 * Typically, fields that require matches need to match exactly if both sides have a value 
25047 	 * for that field. If both sides specify a value and those values differ, that is
25048 	 * a strong non-match. If one side does not have a value and the other does, that 
25049 	 * causes a partial match, because the number with the missing field may possibly
25050 	 * have an implied value that matches the other number. For example, the numbers
25051 	 * "650-555-1234" and "555-1234" have a partial match as the local number "555-1234"
25052 	 * might possibly have the same 650 area code as the first number, and might possibly
25053 	 * not. If both side do not specify a value for a particular field, that field is 
25054 	 * considered matching.<p>
25055 	 *  
25056 	 * The values of following fields are ignored when performing matches:
25057 	 * 
25058 	 * <ul>
25059 	 * <li>vsc
25060 	 * <li>iddPrefix
25061 	 * <li>cic
25062 	 * <li>trunkAccess
25063 	 * </ul>
25064 	 * 
25065 	 * The values of the following fields matter if they do not match:
25066 	 *   
25067 	 * <ul>
25068 	 * <li>countryCode - A difference causes a moderately strong problem except for 
25069 	 * certain countries where there is a way to access the same subscriber via IDD 
25070 	 * and via intranetwork dialling
25071 	 * <li>mobilePrefix - A difference causes a possible non-match
25072 	 * <li>serviceCode - A difference causes a possible non-match
25073 	 * <li>areaCode - A difference causes a possible non-match
25074 	 * <li>subscriberNumber - A difference causes a very strong non-match
25075 	 * <li>extension - A difference causes a minor non-match
25076 	 * </ul>
25077 	 *  
25078 	 * @param {string|ilib.PhoneNumber} other other phone number to compare this one to
25079 	 * @return {number} non-negative integer describing the percentage quality of the 
25080 	 * match. 100 means a very strong match (100%), and lower numbers are less and 
25081 	 * less strong, down to 0 meaning not at all a match. 
25082 	 */
25083 	compare: function (other) {
25084 		var match = 100,
25085 			FRdepartments = {"590":1, "594":1, "596":1, "262":1},
25086 			ITcountries = {"378":1, "379":1},
25087 			thisPrefix,
25088 			otherPrefix,
25089 			currentCountryCode = 0;
25090 
25091 		if (typeof this.locale.region === "string") {
25092 			currentCountryCode = this.locale._mapRegiontoCC(this.locale.region);
25093 		}
25094 		
25095 		// subscriber number must be present and must match
25096 		if (!this.subscriberNumber || !other.subscriberNumber || this.subscriberNumber !== other.subscriberNumber) {
25097 			return 0;
25098 		}
25099 
25100 		// extension must match if it is present
25101 		if (this._xor(this.extension, other.extension) || this.extension !== other.extension) {
25102 			return 0;
25103 		}
25104 
25105 		if (this._xor(this.countryCode, other.countryCode)) {
25106 			// if one doesn't have a country code, give it some demerit points, but if the
25107 			// one that has the country code has something other than the current country
25108 			// add even more. Ignore the special cases where you can dial the same number internationally or via 
25109 			// the local numbering system
25110 			switch (this.locale.getRegion()) {
25111 			case 'FR':
25112 				if (this.countryCode in FRdepartments || other.countryCode in FRdepartments) {
25113 					if (this.areaCode !== other.areaCode || this.mobilePrefix !== other.mobilePrefix) {
25114 						match -= 100;
25115 					}
25116 				} else {
25117 					match -= 16;
25118 				}
25119 				break;
25120 			case 'IT':
25121 				if (this.countryCode in ITcountries || other.countryCode in ITcountries) { 
25122 					if (this.areaCode !== other.areaCode) {
25123 						match -= 100;
25124 					}
25125 				} else {
25126 					match -= 16;
25127 				}
25128 				break;
25129 			default:
25130 				match -= 16;
25131 				if ((this.countryCode !== undefined && this.countryCode !== currentCountryCode) || 
25132 					(other.countryCode !== undefined && other.countryCode !== currentCountryCode)) {
25133 					match -= 16;
25134 				}
25135 			}
25136 		} else if (this.countryCode !== other.countryCode) {
25137 			// ignore the special cases where you can dial the same number internationally or via 
25138 			// the local numbering system
25139 			if (other.countryCode === '33' || this.countryCode === '33') {
25140 				// france
25141 				if (this.countryCode in FRdepartments || other.countryCode in FRdepartments) {
25142 					if (this.areaCode !== other.areaCode || this.mobilePrefix !== other.mobilePrefix) {
25143 						match -= 100;
25144 					}
25145 				} else {
25146 					match -= 100;
25147 				}
25148 			} else if (this.countryCode === '39' || other.countryCode === '39') {
25149 				// italy
25150 				if (this.countryCode in ITcountries || other.countryCode in ITcountries) { 
25151 					if (this.areaCode !== other.areaCode) {
25152 						match -= 100;
25153 					}
25154 				} else {
25155 					match -= 100;
25156 				}
25157 			} else {
25158 				match -= 100;
25159 			}
25160 		}
25161 
25162 		if (this._xor(this.serviceCode, other.serviceCode)) {
25163 			match -= 20;
25164 		} else if (this.serviceCode !== other.serviceCode) {
25165 			match -= 100;
25166 		}
25167 
25168 		if (this._xor(this.mobilePrefix, other.mobilePrefix)) {
25169 			match -= 20;
25170 		} else if (this.mobilePrefix !== other.mobilePrefix) {
25171 			match -= 100;
25172 		}
25173 
25174 		if (this._xor(this.areaCode, other.areaCode)) {
25175 			// one has an area code, the other doesn't, so dock some points. It could be a match if the local
25176 			// number in the one number has the same implied area code as the explicit area code in the other number.
25177 			match -= 12;
25178 		} else if (this.areaCode !== other.areaCode) {
25179 			match -= 100;
25180 		}
25181 
25182 		thisPrefix = this._getPrefix();
25183 		otherPrefix = other._getPrefix();
25184 		
25185 		if (thisPrefix && otherPrefix && thisPrefix !== otherPrefix) {
25186 			match -= 100;
25187 		}
25188 		
25189 		// make sure we are between 0 and 100
25190 		if (match < 0) {
25191 			match = 0;	
25192 		} else if (match > 100) {
25193 			match = 100;
25194 		}
25195 
25196 		return match;
25197 	},
25198 	
25199 	/**
25200 	 * Determine whether or not the other phone number is exactly equal to the current one.<p>
25201 	 *  
25202 	 * The difference between the compare method and the equals method is that the compare 
25203 	 * method compares normalized numbers with each other and returns the degree of match,
25204 	 * whereas the equals operator returns true iff the two numbers contain the same fields
25205 	 * and the fields are exactly the same. Functions and other non-phone number properties
25206 	 * are not compared.
25207 	 * @param {string|ilib.PhoneNumber} other another phone number to compare to this one
25208 	 * @return {boolean} true if the numbers are the same, false otherwise
25209 	 */
25210 	equals: function equals(other) {
25211 		if (other.locale && this.locale && !this.locale.equals(other.locale) && (!this.countryCode || !other.countryCode)) {
25212 			return false;
25213 		}
25214 		
25215 		for (var p in other) {
25216 			if (p !== undefined && this[p] !== undefined && typeof(this[p]) !== 'object') {
25217 				if (other[p] === undefined) {
25218 					/*console.error("PhoneNumber.equals: other is missing property " + p + " which has the value " + this[p] + " in this");
25219 					console.error("this is : " + JSON.stringify(this));
25220 					console.error("other is: " + JSON.stringify(other));*/
25221 					return false;
25222 				}
25223 				if (this[p] !== other[p]) {
25224 					/*console.error("PhoneNumber.equals: difference in property " + p);
25225 					console.error("this is : " + JSON.stringify(this));
25226 					console.error("other is: " + JSON.stringify(other));*/
25227 					return false;
25228 				}
25229 			}
25230 		}
25231 		for (var p in other) {
25232 			if (p !== undefined && other[p] !== undefined && typeof(other[p]) !== 'object') {
25233 				if (this[p] === undefined) {
25234 					/*console.error("PhoneNumber.equals: this is missing property " + p + " which has the value " + other[p] + " in the other");
25235 					console.error("this is : " + JSON.stringify(this));
25236 					console.error("other is: " + JSON.stringify(other));*/
25237 					return false;
25238 				}
25239 				if (this[p] !== other[p]) {
25240 					/*console.error("PhoneNumber.equals: difference in property " + p);
25241 					console.error("this is : " + JSON.stringify(this));
25242 					console.error("other is: " + JSON.stringify(other));*/
25243 					return false;
25244 				}
25245 			}
25246 		}
25247 		return true;
25248 	},
25249 	
25250 
25251 	/**
25252 	 * @private
25253 	 * @param {{
25254 	 *   mcc:string,
25255 	 *   defaultAreaCode:string,
25256 	 *   country:string,
25257 	 *   networkType:string,
25258 	 *   assistedDialing:boolean,
25259 	 *   sms:boolean,
25260 	 *   manualDialing:boolean
25261 	 * }} options an object containing options to help in normalizing. 
25262 	 * @param {ilib.PhoneNumber} norm
25263 	 * @param {ilib.Locale.PhoneLoc} homeLocale
25264 	 * @param {ilib.Locale.PhoneLoc} currentLocale
25265 	 * @param {ilib.NumPlan} currentPlan
25266 	 * @param {ilib.Locale.PhoneLoc} destinationLocale
25267 	 * @param {ilib.NumPlan} destinationPlan
25268 	 * @param {boolean} sync
25269 	 * @param {Object|undefined} loadParams
25270 	 */
25271 	_doNormalize: function(options, norm, homeLocale, currentLocale, currentPlan, destinationLocale, destinationPlan, sync, loadParams) {
25272 		var formatted = "";
25273 		
25274 		if (!norm.invalid && options && options.assistedDialing) {
25275 			// don't normalize things that don't have subscriber numbers. Also, don't normalize
25276 			// manually dialed local numbers. Do normalize local numbers in contact entries.
25277 			if (norm.subscriberNumber && 
25278 					(!options.manualDialing ||
25279 					 norm.iddPrefix ||
25280 					 norm.countryCode ||
25281 					 norm.trunkAccess)) {
25282 				// console.log("normalize: assisted dialling normalization of " + JSON.stringify(norm));
25283 				if (currentLocale.getRegion() !== destinationLocale.getRegion()) {
25284 					// we are currently calling internationally
25285 					if (!norm._hasPrefix() && 
25286 							options.defaultAreaCode && 
25287 							destinationLocale.getRegion() === homeLocale.getRegion() &&
25288 							(!destinationPlan.getFieldLength("minLocalLength") || 
25289 								norm.subscriberNumber.length >= destinationPlan.getFieldLength("minLocalLength"))) {
25290 						// area code is required when dialling from international, but only add it if we are dialing
25291 						// to our home area. Otherwise, the default area code is not valid!
25292 						norm.areaCode = options.defaultAreaCode;
25293 						if (!destinationPlan.getSkipTrunk() && destinationPlan.getTrunkCode()) {
25294 							// some phone systems require the trunk access code, even when dialling from international
25295 							norm.trunkAccess = destinationPlan.getTrunkCode();
25296 						}
25297 					}
25298 					
25299 					if (norm.trunkAccess && destinationPlan.getSkipTrunk()) {
25300 						// on some phone systems, the trunk access code is dropped when dialling from international
25301 						delete norm.trunkAccess;
25302 					}
25303 					
25304 					// make sure to get the country code for the destination region, not the current region!
25305 					if (options.sms) {
25306 						if (homeLocale.getRegion() === "US" && currentLocale.getRegion() !== "US") {
25307 							if (destinationLocale.getRegion() !== "US") {
25308 								norm.iddPrefix = "011"; // non-standard code to make it go through the US first
25309 								norm.countryCode = norm.countryCode || homeLocale._mapRegiontoCC(destinationLocale.getRegion());
25310 							} else if (options.networkType === "cdma") {
25311 								delete norm.iddPrefix;
25312 								delete norm.countryCode;
25313 								if (norm.areaCode) {
25314 									norm.trunkAccess = "1";
25315 								}
25316 							} else if (norm.areaCode) {
25317 								norm.iddPrefix = "+";
25318 								norm.countryCode = "1";
25319 								delete norm.trunkAccess;
25320 							}
25321 						} else {
25322 							norm.iddPrefix = (options.networkType === "cdma") ? currentPlan.getIDDCode() : "+";
25323 							norm.countryCode = norm.countryCode || homeLocale._mapRegiontoCC(destinationLocale.region);
25324 						}
25325 					} else if (norm._hasPrefix() && !norm.countryCode) {
25326 						norm.countryCode = homeLocale._mapRegiontoCC(destinationLocale.region);
25327 					}
25328 
25329 					if (norm.countryCode && !options.sms) {
25330 						// for CDMA, make sure to get the international dialling access code for the current region, not the destination region
25331 						// all umts carriers support plus dialing
25332 						norm.iddPrefix = (options.networkType === "cdma") ? currentPlan.getIDDCode() : "+";
25333 					}
25334 				} else {
25335 					// console.log("normalize: dialing within the country");
25336 					if (options.defaultAreaCode) {
25337 						if (destinationPlan.getPlanStyle() === "open") {
25338 							if (!norm.trunkAccess && norm._hasPrefix() && destinationPlan.getTrunkCode()) {
25339 								// call is not local to this area code, so you have to dial the trunk code and the area code
25340 								norm.trunkAccess = destinationPlan.getTrunkCode();
25341 							}
25342 						} else {
25343 							// In closed plans, you always have to dial the area code, even if the call is local.
25344 							if (!norm._hasPrefix()) {
25345 								if (destinationLocale.getRegion() === homeLocale.getRegion()) {
25346 									norm.areaCode = options.defaultAreaCode;
25347 									if (destinationPlan.getTrunkRequired() && destinationPlan.getTrunkCode()) {
25348 										norm.trunkAccess = norm.trunkAccess || destinationPlan.getTrunkCode();
25349 									}
25350 								}
25351 							} else {
25352 								if (destinationPlan.getTrunkRequired() && destinationPlan.getTrunkCode()) {
25353 									norm.trunkAccess = norm.trunkAccess || destinationPlan.getTrunkCode();
25354 								}
25355 							}
25356 						}
25357 					}
25358 					
25359 					if (options.sms &&
25360 							homeLocale.getRegion() === "US" && 
25361 							currentLocale.getRegion() !== "US") {
25362 						norm.iddPrefix = "011"; // make it go through the US first
25363 						if (destinationPlan.getSkipTrunk() && norm.trunkAccess) {
25364 							delete norm.trunkAccess;
25365 						}
25366 					} else if (norm.iddPrefix || norm.countryCode) {
25367 						// we are in our destination country, so strip the international dialling prefixes
25368 						delete norm.iddPrefix;
25369 						delete norm.countryCode;
25370 						
25371 						if ((destinationPlan.getPlanStyle() === "open" || destinationPlan.getTrunkRequired()) && destinationPlan.getTrunkCode()) {
25372 							norm.trunkAccess = destinationPlan.getTrunkCode();
25373 						}
25374 					}
25375 				}
25376 			}
25377 		} else if (!norm.invalid) {
25378 			// console.log("normalize: non-assisted normalization");
25379 			if (!norm._hasPrefix() && options && options.defaultAreaCode && destinationLocale.getRegion() === homeLocale.region) {
25380 				norm.areaCode = options.defaultAreaCode;
25381 			}
25382 			
25383 			if (!norm.countryCode && norm._hasPrefix()) {
25384 				norm.countryCode = homeLocale._mapRegiontoCC(destinationLocale.getRegion());
25385 			}
25386 
25387 			if (norm.countryCode) {
25388 				if (options && options.networkType && options.networkType === "cdma") {
25389 					norm.iddPrefix = currentPlan.getIDDCode(); 
25390 				} else {
25391 					// all umts carriers support plus dialing
25392 					norm.iddPrefix = "+";
25393 				}
25394 		
25395 				if (destinationPlan.getSkipTrunk() && norm.trunkAccess) {
25396 					delete norm.trunkAccess;
25397 				} else if (!destinationPlan.getSkipTrunk() && !norm.trunkAccess && destinationPlan.getTrunkCode()) {
25398 					norm.trunkAccess = destinationPlan.getTrunkCode();
25399 				}
25400 			}
25401 		}
25402 		
25403 		// console.info("normalize: after normalization, the normalized phone number is: " + JSON.stringify(norm));
25404 		formatted = norm._join();
25405 
25406 		return formatted;
25407 	},
25408 	
25409 	/**
25410 	 * @private
25411 	 * @param {{
25412 	 *   mcc:string,
25413 	 *   defaultAreaCode:string,
25414 	 *   country:string,
25415 	 *   networkType:string,
25416 	 *   assistedDialing:boolean,
25417 	 *   sms:boolean,
25418 	 *   manualDialing:boolean
25419 	 * }} options an object containing options to help in normalizing. 
25420 	 * @param {ilib.PhoneNumber} norm
25421 	 * @param {ilib.Locale.PhoneLoc} homeLocale
25422 	 * @param {ilib.Locale.PhoneLoc} currentLocale
25423 	 * @param {ilib.NumPlan} currentPlan
25424 	 * @param {ilib.Locale.PhoneLoc} destinationLocale
25425 	 * @param {ilib.NumPlan} destinationPlan
25426 	 * @param {boolean} sync
25427 	 * @param {Object|undefined} loadParams
25428 	 * @param {function(string)} callback
25429 	 */
25430 	_doReparse: function(options, norm, homeLocale, currentLocale, currentPlan, destinationLocale, destinationPlan, sync, loadParams, callback) {
25431 		var formatted, 
25432 			tempRegion;
25433 		
25434 		if (options &&
25435 				options.assistedDialing &&
25436 				!norm.trunkAccess && 
25437 				!norm.iddPrefix &&
25438 				norm.subscriberNumber && 
25439 				norm.subscriberNumber.length > destinationPlan.getFieldLength("maxLocalLength")) {
25440 
25441 			// numbers that are too long are sometimes international direct dialed numbers that
25442 			// are missing the IDD prefix. So, try reparsing it using a plus in front to see if that works.
25443 			new ilib.PhoneNumber("+" + this._join(), {
25444 				locale: this.locale,
25445 				sync: sync,
25446 				loadParms: loadParams,
25447 				onLoad: ilib.bind(this, function (data) {
25448 					tempRegion = (data.countryCode && data.locale._mapCCtoRegion(data.countryCode));
25449 
25450 					if (tempRegion && tempRegion !== "unknown" && tempRegion !== "SG") {
25451 						// only use it if it is a recognized country code. Singapore (SG) is a special case.
25452 						norm = data;
25453 						destinationLocale = data.destinationLocale;
25454 						destinationPlan = data.destinationPlan;
25455 					}
25456 					
25457 					formatted = this._doNormalize(options, norm, homeLocale, currentLocale, currentPlan, destinationLocale, destinationPlan, sync, loadParams);
25458 					if (typeof(callback) === 'function') {
25459 						callback(formatted);
25460 					}
25461 				})
25462 			});
25463 		} else if (options && options.assistedDialing && norm.invalid && currentLocale.region !== norm.locale.region) {
25464 			// if this number is not valid for the locale it was parsed with, try again with the current locale
25465 			// console.log("norm is invalid. Attempting to reparse with the current locale");
25466 
25467 			new ilib.PhoneNumber(this._join(), {
25468 				locale: currentLocale,
25469 				sync: sync,
25470 				loadParms: loadParams,
25471 				onLoad: ilib.bind(this, function (data) {
25472 					if (data && !data.invalid) {
25473 						norm = data;
25474 					}
25475 					
25476 					formatted = this._doNormalize(options, norm, homeLocale, currentLocale, currentPlan, destinationLocale, destinationPlan, sync, loadParams);
25477 					if (typeof(callback) === 'function') {
25478 						callback(formatted);
25479 					}
25480 				})
25481 			});
25482 		} else {
25483 			formatted = this._doNormalize(options, norm, homeLocale, currentLocale, currentPlan, destinationLocale, destinationPlan, sync, loadParams);
25484 			if (typeof(callback) === 'function') {
25485 				callback(formatted);
25486 			}
25487 		}
25488 	},
25489 	
25490 	/**
25491 	 * This function normalizes the current phone number to a canonical format and returns a
25492 	 * string with that phone number. If parts are missing, this function attempts to fill in 
25493 	 * those parts.<p>
25494 	 * 	  
25495 	 * The options object contains a set of properties that can possibly help normalize
25496 	 * this number by providing "extra" information to the algorithm. The options
25497 	 * parameter may be null or an empty object if no hints can be determined before
25498 	 * this call is made. If any particular hint is not
25499 	 * available, it does not need to be present in the options object.<p>
25500 	 * 
25501 	 * The following is a list of hints that the algorithm will look for in the options
25502 	 * object:
25503 	 * 
25504 	 * <ul>
25505 	 * <li><i>mcc</i> the mobile carrier code of the current network upon which this 
25506 	 * phone is operating. This is translated into an IDD country code. This is 
25507 	 * useful if the number being normalized comes from CNAP (callerid) and the
25508 	 * MCC is known.
25509 	 * <li><i>defaultAreaCode</i> the area code of the phone number of the current
25510 	 * device, if available. Local numbers in a person's contact list are most 
25511 	 * probably in this same area code.
25512 	 * <li><i>country</i> the 2 letter ISO 3166 code of the country if it is
25513 	 * known from some other means such as parsing the physical address of the
25514 	 * person associated with the phone number, or the from the domain name 
25515 	 * of the person's email address
25516 	 * <li><i>networkType</i> specifies whether the phone is currently connected to a
25517 	 * CDMA network or a UMTS network. Valid values are the strings "cdma" and "umts".
25518 	 * If one of those two strings are not specified, or if this property is left off
25519 	 * completely, this method will assume UMTS.
25520 	 * </ul>
25521 	 * 
25522 	 * The following are a list of options that control the behaviour of the normalization:
25523 	 * 
25524 	 * <ul>
25525 	 * <li><i>assistedDialing</i> if this is set to true, the number will be normalized
25526 	 * so that it can dialled directly on the type of network this phone is 
25527 	 * currently connected to. This allows customers to dial numbers or use numbers 
25528 	 * in their contact list that are specific to their "home" region when they are 
25529 	 * roaming and those numbers would not otherwise work with the current roaming 
25530 	 * carrier as they are. The home region is 
25531 	 * specified as the phoneRegion system preference that is settable in the 
25532 	 * regional settings app. With assisted dialling, this method will add or 
25533 	 * remove international direct dialling prefixes and country codes, as well as
25534 	 * national trunk access codes, as required by the current roaming carrier and the
25535 	 * home region in order to dial the number properly. If it is not possible to 
25536 	 * construct a full international dialling sequence from the options and hints given,
25537 	 * this function will not modify the phone number, and will return "undefined".
25538 	 * If assisted dialling is false or not specified, then this method will attempt
25539 	 * to add all the information it can to the number so that it is as fully
25540 	 * specified as possible. This allows two numbers to be compared more easily when
25541 	 * those two numbers were otherwise only partially specified.
25542 	 * <li><i>sms</i> set this option to true for the following conditions: 
25543 	 *   <ul>
25544 	 *   <li>assisted dialing is turned on
25545 	 *   <li>the phone number represents the destination of an SMS message
25546 	 *   <li>the phone is UMTS 
25547 	 *   <li>the phone is SIM-locked to its carrier
25548 	 *   </ul> 
25549 	 * This enables special international direct dialling codes to route the SMS message to
25550 	 * the correct carrier. If assisted dialling is not turned on, this option has no
25551 	 * affect.
25552 	 * <li><i>manualDialing</i> set this option to true if the user is entering this number on
25553 	 * the keypad directly, and false when the number comes from a stored location like a 
25554 	 * contact entry or a call log entry. When true, this option causes the normalizer to 
25555 	 * not perform any normalization on numbers that look like local numbers in the home 
25556 	 * country. If false, all numbers go through normalization. This option only has an effect
25557 	 * when the assistedDialing option is true as well, otherwise it is ignored.
25558 	 * </ul> 
25559 	 * 
25560 	 * If both a set of options and a locale are given, and they offer conflicting
25561 	 * information, the options will take precedence. The idea is that the locale
25562 	 * tells you the region setting that the user has chosen (probably in 
25563 	 * firstuse), whereas the the hints are more current information such as
25564 	 * where the phone is currently operating (the MCC).<p> 
25565 	 * 
25566 	 * This function performs the following types of normalizations with assisted
25567 	 * dialling turned on:
25568 	 * 
25569 	 * <ol>
25570 	 * <li>If the current location of the phone matches the home country, this is a
25571 	 * domestic call.
25572 	 *   <ul> 
25573 	 *   <li>Remove any iddPrefix and countryCode fields, as they are not needed
25574 	 *   <li>Add in a trunkAccess field that may be necessary to call a domestic numbers 
25575 	 *     in the home country
25576 	 *   </ul>
25577 	 * <li> If the current location of the phone does not match the home country,
25578 	 * attempt to form a whole international number.
25579 	 *   <ul>
25580 	 *   <li>Add in the area code if it is missing from the phone number and the area code
25581 	 *     of the current phone is available in the hints
25582 	 *   <li>Add the country dialling code for the home country if it is missing from the 
25583 	 *     phone number
25584 	 *   <li>Add or replace the iddPrefix with the correct one for the current country. The
25585 	 *     phone number will have been parsed with the settings for the home country, so
25586 	 *     the iddPrefix may be incorrect for the
25587 	 *     current country. The iddPrefix for the current country can be "+" if the phone 
25588 	 *     is connected to a UMTS network, and either a "+" or a country-dependent 
25589 	 *     sequences of digits for CDMA networks.
25590 	 *   </ul>
25591 	 * </ol>
25592 	 * 
25593 	 * This function performs the following types of normalization with assisted
25594 	 * dialling turned off:
25595 	 * 
25596 	 * <ul>
25597 	 * <li>Normalize the international direct dialing prefix to be a plus or the
25598 	 * international direct dialling access code for the current country, depending
25599 	 * on the network type.
25600 	 * <li>If a number is a local number (ie. it is missing its area code), 
25601 	 * use a default area code from the hints if available. CDMA phones always know their area 
25602 	 * code, and GSM/UMTS phones know their area code in many instances, but not always 
25603 	 * (ie. not on Vodaphone or Telcel phones). If the default area code is not available, 
25604 	 * do not add it.
25605 	 * <li>In assisted dialling mode, if a number is missing its country code, 
25606 	 * use the current MCC number if
25607 	 * it is available to figure out the current country code, and prepend that 
25608 	 * to the number. If it is not available, leave it off. Also, use that 
25609 	 * country's settings to parse the number instead of the current format 
25610 	 * locale.
25611 	 * <li>For North American numbers with an area code but no trunk access 
25612 	 * code, add in the trunk access code.
25613 	 * <li>For other countries, if the country code is added in step 3, remove the 
25614 	 * trunk access code when required by that country's conventions for 
25615 	 * international calls. If the country requires a trunk access code for 
25616 	 * international calls and it doesn't exist, add one.
25617 	 * </ul>
25618 	 *  
25619 	 * This method modifies the current object, and also returns a string 
25620 	 * containing the normalized phone number that can be compared directly against
25621 	 * other normalized numbers. The canonical format for phone numbers that is 
25622 	 * returned from thhomeLocaleis method is simply an uninterrupted and unformatted string 
25623 	 * of dialable digits.
25624 	 * 
25625 	 * @param {{
25626 	 *   mcc:string,
25627 	 *   defaultAreaCode:string,
25628 	 *   country:string,
25629 	 *   networkType:string,
25630 	 *   assistedDialing:boolean,
25631 	 *   sms:boolean,
25632 	 *   manualDialing:boolean
25633 	 * }} options an object containing options to help in normalizing. 
25634 	 * @return {string|undefined} the normalized string, or undefined if the number
25635 	 * could not be normalized
25636 	 */
25637 	normalize: function(options) {
25638 		var norm,
25639 			sync = true,
25640 			loadParams = {};
25641 			
25642 
25643 		if (options) {
25644 			if (typeof(options.sync) !== 'undefined') {
25645 				sync = (options.sync == true);
25646 			}
25647 			
25648 			if (options.loadParams) {
25649 				loadParams = options.loadParams;
25650 			}
25651 		}
25652 		
25653 		// Clone this number, so we don't mess with the original.
25654 		// No need to do this asynchronously because it's a copy constructor which doesn't 
25655 		// load any extra files.
25656 		norm = new ilib.PhoneNumber(this);
25657 
25658 		var normalized;
25659 		
25660 		if (options && (typeof(options.mcc) !== 'undefined' || typeof(options.country) !== 'undefined')) {
25661 			new ilib.Locale.PhoneLoc({
25662 				mcc: options.mcc,
25663 				countryCode: options.countryCode,
25664 				locale: this.locale,
25665 				sync: sync,
25666 				loadParams: loadParams,
25667 				onLoad: ilib.bind(this, function(loc) {
25668 					new ilib.NumPlan({
25669 						locale: loc,
25670 						sync: sync,
25671 						loadParms: loadParams,
25672 						onLoad: ilib.bind(this, function (plan) {
25673 							this._doReparse(options, norm, this.locale, loc, plan, this.destinationLocale, this.destinationPlan, sync, loadParams, function (fmt) {
25674 								normalized = fmt;
25675 								
25676 								if (options && typeof(options.onLoad) === 'function') {
25677 									options.onLoad(fmt);
25678 								}
25679 							});
25680 						})
25681 					});
25682 				})
25683 			});
25684 		} else {
25685 			this._doReparse(options, norm, this.locale, this.locale, this.plan, this.destinationLocale, this.destinationPlan, sync, loadParams, function (fmt) {
25686 				normalized = fmt;
25687 				
25688 				if (options && typeof(options.onLoad) === 'function') {
25689 					options.onLoad(fmt);
25690 				}
25691 			});
25692 		}
25693 
25694 		// return the value for the synchronous case
25695 		return normalized;
25696 	}
25697 };
25698 /*
25699  * phonefmt.js - Represent a phone number formatter.
25700  * 
25701  * Copyright © 2014, JEDLSoft
25702  *
25703  * Licensed under the Apache License, Version 2.0 (the "License");
25704  * you may not use this file except in compliance with the License.
25705  * You may obtain a copy of the License at
25706  *
25707  *     http://www.apache.org/licenses/LICENSE-2.0
25708  *
25709  * Unless required by applicable law or agreed to in writing, software
25710  * distributed under the License is distributed on an "AS IS" BASIS,
25711  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25712  *
25713  * See the License for the specific language governing permissions and
25714  * limitations under the License.
25715  */
25716 
25717 /*
25718 !depends 
25719 ilibglobal.js 
25720 locale.js 
25721 localeinfo.js
25722 phone/numplan.js
25723 phone/phonenum.js
25724 */
25725 
25726 // !data phonefmt
25727 
25728 /**
25729  * @class
25730  * Create a new phone number formatter object that formats numbers according to the parameters.<p>
25731  * 
25732  * The options object can contain zero or more of the following parameters:
25733  *
25734  * <ul>
25735  * <li><i>locale</i> locale to use to format this number, or undefined to use the default locale
25736  * <li><i>style</i> the name of style to use to format numbers, or undefined to use the default style
25737  * <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
25738  *
25739  * <li><i>onLoad</i> - a callback function to call when the locale data is fully loaded and the address has been 
25740  * parsed. When the onLoad option is given, the address formatter object 
25741  * will attempt to load any missing locale data using the ilib loader callback.
25742  * When the constructor is done (even if the data is already preassembled), the 
25743  * onLoad function is called with the current instance as a parameter, so this
25744  * callback can be used with preassembled or dynamic loading or a mix of the two. 
25745  * 
25746  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
25747  * asynchronously. If this option is given as "false", then the "onLoad"
25748  * callback must be given, as the instance returned from this constructor will
25749  * not be usable for a while. 
25750  *
25751  * <li><i>loadParams</i> - an object containing parameters to pass to the 
25752  * loader callback function when locale data is missing. The parameters are not
25753  * interpretted or modified in any way. They are simply passed along. The object 
25754  * may contain any property/value pairs as long as the calling code is in
25755  * agreement with the loader callback function as to what those parameters mean.
25756  * </ul>
25757  *
25758  * Some regions have more than one style of formatting, and the style parameter
25759  * selects which style the user prefers. An array of style names that this locale
25760  * supports can be found by calling {@link ilib.PhoneFmt.getAvailableStyles}. 
25761  * Example phone numbers can be retrieved for each style by calling 
25762  * {@link ilib.PhoneFmt.getStyleExample}.
25763  * <p>
25764  *
25765  * If the MCC is given, numbers will be formatted in the manner of the country
25766  * specified by the MCC. If it is not given, but the locale is, the manner of
25767  * the country in the locale will be used. If neither the locale or MCC are not given,
25768  * then the country of the current ilib locale is used. 
25769  *
25770  * @constructor
25771  * @param {Object} options properties that control how this formatter behaves
25772  */
25773 ilib.PhoneFmt = function(options) {
25774 	this.sync = true;
25775 	this.styleName = 'default',
25776 	this.loadParams = {};
25777 
25778 	var locale = new ilib.Locale();
25779 
25780 	if (options) {
25781 		if (options.locale) {
25782 			locale = options.locale;
25783 		}
25784 
25785 		if (typeof(options.sync) !== 'undefined') {
25786 			this.sync = (options.sync == true);
25787 		}
25788 
25789 		if (options.loadParams) {
25790 			this.loadParams = options.loadParams;
25791 		}
25792 
25793 		if (options.style) {
25794 			this.style = options.style;
25795 		}
25796 	}
25797 
25798 	new ilib.Locale.PhoneLoc({
25799 		locale: locale,
25800 		mcc: options && options.mcc,
25801 		countryCode: options && options.countryCode,
25802 		onLoad: ilib.bind(this, function (data) {
25803 			/** @type {ilib.Locale.PhoneLoc} */
25804 			this.locale = data;
25805 
25806 			new ilib.NumPlan({
25807 				locale: this.locale,
25808 				sync: this.sync,
25809 				loadParms: this.loadParams,
25810 				onLoad: ilib.bind(this, function (plan) {
25811 					/** @type {ilib.NumPlan} */
25812 					this.plan = plan;
25813 
25814 					ilib.loadData({
25815 						name: "phonefmt.json",
25816 						object: ilib.PhoneFmt,
25817 						locale: this.locale, 
25818 						sync: this.sync,
25819 						loadParams: ilib.merge(this.loadParams, {
25820 							returnOne: true
25821 						}),
25822 						callback: ilib.bind(this, function (fmtdata) {
25823 							this.fmtdata = fmtdata;
25824 							
25825 							if (options && typeof(options.onLoad) === 'function') {
25826 								options.onLoad(this);
25827 							}
25828 						})
25829 					});
25830 				})
25831 			});
25832 		})
25833 	});
25834 };
25835 
25836 ilib.PhoneFmt.prototype = {
25837 	/**
25838 	 * 
25839 	 * @protected
25840 	 * @param {string} part
25841 	 * @param {Object} formats
25842 	 * @param {boolean} mustUseAll
25843 	 */
25844 	_substituteDigits: function(part, formats, mustUseAll) {
25845 		var formatString,
25846 			formatted = "",
25847 			partIndex = 0,
25848 			templates,
25849 			i;
25850 
25851 		// console.info("Globalization.Phone._substituteDigits: typeof(formats) is " + typeof(formats));
25852 		if (!part) {
25853 			return formatted;
25854 		}
25855 
25856 		if (typeof(formats) === "object") {
25857 			templates = (typeof(formats.template) !== 'undefined') ? formats.template : formats;
25858 			if (part.length > templates.length) {
25859 				// too big, so just use last resort rule.
25860 				throw "part " + part + " is too big. We do not have a format template to format it.";
25861 			}
25862 			// use the format in this array that corresponds to the digit length of this
25863 			// part of the phone number
25864 			formatString =  templates[part.length-1];
25865 			// console.info("Globalization.Phone._substituteDigits: formats is an Array: " + JSON.stringify(formats));
25866 		} else {
25867 			formatString = formats;
25868 		}
25869 
25870 		for (i = 0; i < formatString.length; i++) {
25871 			if (formatString.charAt(i) === "X") {
25872 				formatted += part.charAt(partIndex);
25873 				partIndex++;
25874 			} else {
25875 				formatted += formatString.charAt(i);
25876 			}
25877 		}
25878 		
25879 		if (mustUseAll && partIndex < part.length-1) {
25880 			// didn't use the whole thing in this format? Hmm... go to last resort rule
25881 			throw "too many digits in " + part + " for format " + formatString;
25882 		}
25883 		
25884 		return formatted;
25885 	},
25886 	
25887 	/**
25888 	 * Returns the style with the given name, or the default style if there
25889 	 * is no style with that name.
25890 	 * @protected
25891 	 * @return {{example:string,whole:Object.<string,string>,partial:Object.<string,string>}|Object.<string,string>}
25892 	 */
25893 	_getStyle: function (name, fmtdata) {
25894 		return fmtdata[name] || fmtdata["default"];
25895 	},
25896 
25897 	/**
25898 	 * Do the actual work of formatting the phone number starting at the given
25899 	 * field in the regular field order.
25900 	 * 
25901 	 * @param {!ilib.PhoneNumber} number
25902 	 * @param {{
25903 	 *   partial:boolean,
25904 	 *   style:string,
25905 	 *   mcc:string,
25906 	 *   locale:(string|ilib.Locale),
25907 	 *   sync:boolean,
25908 	 *   loadParams:Object,
25909 	 *   onLoad:function(string)
25910 	 * }} options Parameters which control how to format the number
25911 	 * @param {number} startField
25912 	 */
25913 	_doFormat: function(number, options, startField, locale, fmtdata, callback) {
25914 		var sync = true,
25915 			loadParams = {},
25916 			temp, 
25917 			templates, 
25918 			fieldName, 
25919 			countryCode, 
25920 			isWhole, 
25921 			style,
25922 			formatted = "",
25923 			styleTemplates,
25924 			lastFieldName;
25925 	
25926 		if (options) {
25927 			if (typeof(options.sync) !== 'undefined') {
25928 				sync = (options.sync == true);				
25929 			}
25930 		
25931 			if (options.loadParams) {
25932 				loadParams = options.loadParams;
25933 			}
25934 		}
25935 	
25936 		style = this.style; // default style for this formatter
25937 
25938 		// figure out what style to use for this type of number
25939 		if (number.countryCode) {
25940 			// dialing from outside the country
25941 			// check to see if it to a mobile number because they are often formatted differently
25942 			style = (number.mobilePrefix) ? "internationalmobile" : "international";
25943 		} else if (number.mobilePrefix !== undefined) {
25944 			style = "mobile";
25945 		} else if (number.serviceCode !== undefined && typeof(fmtdata["service"]) !== 'undefined') {
25946 			// if there is a special format for service numbers, then use it
25947 			style = "service";
25948 		}
25949 
25950 		isWhole = (!options || !options.partial);
25951 		styleTemplates = this._getStyle(style, fmtdata);
25952 		
25953 		// console.log("Style ends up being " + style + " and using subtype " + (isWhole ? "whole" : "partial"));
25954 		styleTemplates = (isWhole ? styleTemplates.whole : styleTemplates.partial) || styleTemplates;
25955 
25956 		for (var i = startField; i < ilib.PhoneNumber._fieldOrder.length; i++) {
25957 			fieldName = ilib.PhoneNumber._fieldOrder[i];
25958 			// console.info("format: formatting field " + fieldName + " value: " + number[fieldName]);
25959 			if (number[fieldName] !== undefined) {
25960 				if (styleTemplates[fieldName] !== undefined) {
25961 					templates = styleTemplates[fieldName];
25962 					if (fieldName === "trunkAccess") {
25963 						if (number.areaCode === undefined && number.serviceCode === undefined && number.mobilePrefix === undefined) {
25964 							templates = "X";
25965 						}
25966 					}
25967 					if (lastFieldName && typeof(styleTemplates[lastFieldName].suffix) !== 'undefined') {
25968 						if (fieldName !== "extension" && number[fieldName].search(/[xwtp,;]/i) <= -1) {
25969 							formatted += styleTemplates[lastFieldName].suffix;	
25970 						}
25971 					}
25972 					lastFieldName = fieldName;
25973 					
25974 					// console.info("format: formatting field " + fieldName + " with templates " + JSON.stringify(templates));
25975 					temp = this._substituteDigits(number[fieldName], templates, (fieldName === "subscriberNumber"));
25976 					// console.info("format: formatted is: " + temp);
25977 					formatted += temp;
25978 	
25979 					if (fieldName === "countryCode") {
25980 						// switch to the new country to format the rest of the number
25981 						countryCode = number.countryCode.replace(/[wWpPtT\+#\*]/g, '');	// fix for NOV-108200
25982 
25983 						new ilib.Locale.PhoneLoc({
25984 							locale: this.locale,
25985 							sync: sync,							
25986 							loadParms: loadParams,
25987 							countryCode: countryCode,
25988 							onLoad: ilib.bind(this, function (/** @type {ilib.Locale.PhoneLoc} */ locale) {
25989 								ilib.loadData({
25990 									name: "phonefmt.json",
25991 									object: ilib.PhoneFmt,
25992 									locale: locale,
25993 									sync: sync,
25994 									loadParams: ilib.merge(loadParams, {
25995 										returnOne: true
25996 									}),
25997 									callback: ilib.bind(this, function (fmtdata) {
25998 										// console.info("format: switching to region " + locale.region + " and style " + style + " to format the rest of the number ");
25999 										
26000 										var subfmt = "";
26001 
26002 										this._doFormat(number, options, i+1, locale, fmtdata, function (subformat) {
26003 											subfmt = subformat;
26004 											if (typeof(callback) === 'function') {
26005 												callback(formatted + subformat);
26006 											}
26007 										});
26008 										
26009 										formatted += subfmt;
26010 									})
26011 								});
26012 							})
26013 						});
26014 						return formatted;
26015 					}
26016 				} else {
26017 					//console.warn("PhoneFmt.format: cannot find format template for field " + fieldName + ", region " + locale.region + ", style " + style);
26018 					// use default of "minimal formatting" so we don't miss parts because of bugs in the format templates
26019 					formatted += number[fieldName];
26020 				}
26021 			}
26022 		}
26023 		
26024 		if (typeof(callback) === 'function') {
26025 			callback(formatted);
26026 		}
26027 
26028 		return formatted;
26029 	},
26030 	
26031 	/**
26032 	 * Format the parts of a phone number appropriately according to the settings in 
26033 	 * this formatter instance.
26034 	 *  
26035 	 * The options can contain zero or more of these properties:
26036 	 * 
26037 	 * <ul>
26038 	 * <li><i>partial</i> boolean which tells whether or not this phone number 
26039 	 * represents a partial number or not. The default is false, which means the number 
26040 	 * represents a whole number. 
26041 	 * <li><i>style</i> style to use to format the number, if different from the 
26042 	 * default style or the style specified in the constructor
26043 	 * <li><i>locale</i> The locale with which to parse the number. This gives a clue as to which
26044      * numbering plan to use.
26045      * <li><i>mcc</i> The mobile carrier code (MCC) associated with the carrier that the phone is 
26046      * currently connected to, if known. This also can give a clue as to which numbering plan to
26047      * use
26048      * <li><i>onLoad</i> - a callback function to call when the date format object is fully 
26049      * loaded. When the onLoad option is given, the DateFmt object will attempt to
26050      * load any missing locale data using the ilib loader callback.
26051      * When the constructor is done (even if the data is already preassembled), the 
26052      * onLoad function is called with the current instance as a parameter, so this
26053      * callback can be used with preassembled or dynamic loading or a mix of the two.
26054      * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
26055      * asynchronously. If this option is given as "false", then the "onLoad"
26056      * callback must be given, as the instance returned from this constructor will
26057      * not be usable for a while.
26058      * <li><i>loadParams</i> - an object containing parameters to pass to the 
26059      * loader callback function when locale data is missing. The parameters are not
26060      * interpretted or modified in any way. They are simply passed along. The object 
26061      * may contain any property/value pairs as long as the calling code is in
26062      * agreement with the loader callback function as to what those parameters mean.
26063 	 * </ul>
26064 	 *      
26065 	 * The partial parameter specifies whether or not the phone number contains
26066 	 * a partial phone number or if it is a whole phone number. A partial 
26067 	 * number is usually a number as the user is entering it with a dial pad. The
26068 	 * reason is that certain types of phone numbers should be formatted differently
26069 	 * depending on whether or not it represents a whole number. Specifically, SMS
26070 	 * short codes are formatted differently.<p>
26071 	 * 
26072 	 * Example: a subscriber number of "48773" in the US would get formatted as:
26073 	 * 
26074 	 * <ul>
26075 	 * <li>partial: 487-73  (perhaps the user is in the process of typing a whole phone 
26076 	 * number such as 487-7379)
26077 	 * <li>whole:   48773   (this is the entire SMS short code)
26078 	 * </ul>
26079 	 * 
26080 	 * Any place in the UI where the user types in phone numbers, such as the keypad in 
26081 	 * the phone app, should pass in partial: true to this formatting routine. All other 
26082 	 * places, such as the call log in the phone app, should pass in partial: false, or 
26083 	 * leave the partial flag out of the parameters entirely. 
26084 	 * 
26085 	 * @param {!ilib.PhoneNumber} number object containing the phone number to format
26086 	 * @param {{
26087 	 *   partial:boolean,
26088 	 *   style:string,
26089 	 *   mcc:string,
26090 	 *   locale:(string|ilib.Locale),
26091 	 *   sync:boolean,
26092 	 *   loadParams:Object,
26093 	 *   onLoad:function(string)
26094 	 * }} options Parameters which control how to format the number
26095 	 * @return {string} Returns the formatted phone number as a string.
26096 	 */
26097 	format: function (number, options) {
26098 		var formatted = "",
26099 		    callback;
26100 
26101 		callback = options && options.onLoad;
26102 
26103 		try {
26104 			this._doFormat(number, options, 0, this.locale, this.fmtdata, function (fmt) {
26105 				formatted = fmt;
26106 				
26107 				if (typeof(callback) === 'function') {
26108 					callback(fmt);
26109 				}
26110 			});
26111 		} catch (e) {
26112 			if (typeof(e) === 'string') { 
26113 				// console.warn("caught exception: " + e + ". Using last resort rule.");
26114 				// if there was some exception, use this last resort rule
26115 				formatted = "";
26116 				for (var field in ilib.PhoneNumber._fieldOrder) {
26117 					if (typeof field === 'string' && typeof ilib.PhoneNumber._fieldOrder[field] === 'string' && number[ilib.PhoneNumber._fieldOrder[field]] !== undefined) {
26118 						// just concatenate without any formatting
26119 						formatted += number[ilib.PhoneNumber._fieldOrder[field]];
26120 						if (ilib.PhoneNumber._fieldOrder[field] === 'countryCode') {
26121 							formatted += ' ';		// fix for NOV-107894
26122 						}
26123 					}
26124 				}
26125 			} else {
26126 				throw e;
26127 			}
26128 			
26129 			if (typeof(callback) === 'function') {
26130 				callback(formatted);
26131 			}
26132 		}
26133 		return formatted;
26134 	},
26135 	
26136 	/**
26137 	 * Return an array of names of all available styles that can be used with the current 
26138 	 * formatter.
26139 	 * @return {Array.<string>} an array of names of styles that are supported by this formatter
26140 	 */
26141 	getAvailableStyles: function () {
26142 		var ret = [],
26143 			style;
26144 
26145 		if (this.fmtdata) {
26146 			for (style in this.fmtdata) {
26147 				if (this.fmtdata[style].example) {
26148 					ret.push(style);
26149 				}
26150 			}
26151 		}
26152 		return ret;
26153 	},
26154 	
26155 	/**
26156 	 * Return an example phone number formatted with the given style.
26157 	 * 
26158 	 * @param {string|undefined} style style to get an example of, or undefined to use
26159 	 * the current default style for this formatter
26160 	 * @return {string|undefined} an example phone number formatted according to the 
26161 	 * given style, or undefined if the style is not recognized or does not have an 
26162 	 * example 
26163 	 */
26164 	getStyleExample: function (style) {
26165 		return this.fmtdata[style].example || undefined;
26166 	}
26167 };
26168 
26169 /*
26170  * phonegeo.js - Represent a phone number geolocator object.
26171  * 
26172  * Copyright © 2014, JEDLSoft
26173  *
26174  * Licensed under the Apache License, Version 2.0 (the "License");
26175  * you may not use this file except in compliance with the License.
26176  * You may obtain a copy of the License at
26177  *
26178  *     http://www.apache.org/licenses/LICENSE-2.0
26179  *
26180  * Unless required by applicable law or agreed to in writing, software
26181  * distributed under the License is distributed on an "AS IS" BASIS,
26182  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26183  *
26184  * See the License for the specific language governing permissions and
26185  * limitations under the License.
26186  */
26187 
26188 /*
26189 !depends 
26190 ilibglobal.js 
26191 locale.js 
26192 localeinfo.js
26193 phone/numplan.js
26194 phone/phoneloc.js
26195 phone/phonenum.js
26196 */
26197 
26198 // !data iddarea area extarea extstates phoneres
26199 
26200 /**
26201  * @class
26202  * Create an instance that can geographically locate a phone number.<p>
26203  * 
26204  * The location of the number is calculated according to the following rules:
26205  * 
26206  * <ol>
26207  * <li>If the areaCode property is undefined or empty, or if the number specifies a 
26208  * country code for which we do not have information, then the area property may be 
26209  * missing from the returned object. In this case, only the country object will be returned.
26210  * 
26211  * <li>If there is no area code, but there is a mobile prefix, service code, or emergency 
26212  * code, then a fixed string indicating the type of number will be returned.
26213  * 
26214  * <li>The country object is filled out according to the countryCode property of the phone
26215  * number. 
26216  * 
26217  * <li>If the phone number does not have an explicit country code, the MCC will be used if
26218  * it is available. The country code can be gleaned directly from the MCC. If the MCC 
26219  * of the carrier to which the phone is currently connected is available, it should be 
26220  * passed in so that local phone numbers will look correct.
26221  * 
26222  * <li>If the country's dialling plan mandates a fixed length for phone numbers, and a 
26223  * particular number exceeds that length, then the area code will not be given on the
26224  * assumption that the number has problems in the first place and we cannot guess
26225  * correctly.
26226  * </ol>
26227  * 
26228  * The returned area property varies in specificity according
26229  * to the locale. In North America, the area is no finer than large parts of states
26230  * or provinces. In Germany and the UK, the area can be as fine as small towns.<p>
26231  * 
26232  * If the number passed in is invalid, no geolocation will be performed. If the location
26233  * information about the country where the phone number is located is not available,
26234  * then the area information will be missing and only the country will be available.<p>
26235  * 
26236  * The options parameter can contain any one of the following properties:
26237  * 
26238  * <ul>
26239  * <li><i>locale</i> The locale parameter is used to load translations of the names of regions and
26240  * areas if available. For example, if the locale property is given as "en-US" (English for USA), 
26241  * but the phone number being geolocated is in Germany, then this class would return the the names
26242  * of the country (Germany) and region inside of Germany in English instead of German. That is, a 
26243  * phone number in Munich and return the country "Germany" and the area code "Munich"
26244  * instead of "Deutschland" and "München". The default display locale is the current ilib locale. 
26245  * If translations are not available, the region and area names are given in English, which should 
26246  * always be available.
26247  * <li><i>mcc</i> The mcc of the current mobile carrier, if known.
26248  * 
26249  * <li><i>onLoad</i> - a callback function to call when the data for the
26250  * locale is fully loaded. When the onLoad option is given, this object 
26251  * will attempt to load any missing locale data using the ilib loader callback.
26252  * When the constructor is done (even if the data is already preassembled), the 
26253  * onLoad function is called with the current instance as a parameter, so this
26254  * callback can be used with preassembled or dynamic loading or a mix of the two. 
26255  * 
26256  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
26257  * asynchronously. If this option is given as "false", then the "onLoad"
26258  * callback must be given, as the instance returned from this constructor will
26259  * not be usable for a while. 
26260  *
26261  * <li><i>loadParams</i> - an object containing parameters to pass to the 
26262  * loader callback function when locale data is missing. The parameters are not
26263  * interpretted or modified in any way. They are simply passed along. The object 
26264  * may contain any property/value pairs as long as the calling code is in
26265  * agreement with the loader callback function as to what those parameters mean.
26266  * </ul>
26267  * 
26268  * @constructor
26269  * @param {Object} options parameters controlling the geolocation of the phone number.
26270  */
26271 ilib.GeoLocator = function(options) {
26272 	var sync = true,
26273 		loadParams = {},
26274 		locale = ilib.getLocale();
26275 
26276 	if (options) {
26277 		if (options.locale) {
26278 			locale = options.locale;
26279 		}
26280 
26281 		if (typeof(options.sync) === 'boolean') {
26282 			sync = options.sync;
26283 		}
26284 		
26285 		if (options.loadParams) {
26286 			loadParams = options.loadParams;
26287 		}
26288 	}
26289 	
26290 	new ilib.Locale.PhoneLoc({
26291 		locale: locale,
26292 		mcc: options && options.mcc,
26293 		countryCode: options && options.countryCode,
26294 		sync: sync,
26295 		loadParams: loadParams,
26296 		onLoad: ilib.bind(this, function (loc) {
26297 			this.locale = loc;
26298 			new ilib.NumPlan({
26299 				locale: this.locale,
26300 				sync: sync,
26301 				loadParams: loadParams,
26302 				onLoad: ilib.bind(this, function (plan) {
26303 					this.plan = plan;
26304 					
26305 					new ilib.ResBundle({
26306 						locale: this.locale,
26307 						name: "phoneres",
26308 						sync: sync,
26309 						loadParams: loadParams,
26310 						onLoad: ilib.bind(this, function (rb) {
26311 							this.rb = rb;
26312 							
26313 							ilib.loadData({
26314 								name: "iddarea.json",
26315 								object: ilib.GeoLocator,
26316 								nonlocale: true,
26317 								sync: sync,
26318 								loadParams: loadParams,
26319 								callback: ilib.bind(this, function (data) {
26320 									this.regiondata = data;
26321 									ilib.loadData({
26322 										name: "area.json",
26323 										object: ilib.GeoLocator,
26324 										locale: this.locale,
26325 										sync: sync,
26326 										loadParams: ilib.merge(loadParams, {
26327 											returnOne: true
26328 										}),
26329 										callback: ilib.bind(this, function (areadata) {
26330 											this.areadata = areadata;
26331 		
26332 											if (options && typeof(options.onLoad) === 'function') {
26333 												options.onLoad(this);
26334 											}
26335 										})
26336 									});
26337 								})
26338 							});
26339 						})
26340 					});
26341 				})
26342 			});
26343 		})
26344 	});
26345 };
26346 
26347 ilib.GeoLocator.prototype = {
26348 	/**
26349 	 * @private
26350 	 * 
26351 	 * Used for locales where the area code is very general, and you need to add in
26352 	 * the initial digits of the subscriber number in order to get the area
26353 	 * 
26354 	 * @param {string} number
26355 	 * @param {Object} stateTable
26356 	 */
26357 	_parseAreaAndSubscriber: function (number, stateTable) {
26358 		var ch,
26359 			i,
26360 			handlerMethod,
26361 			newState,
26362 			prefix = "",
26363 			consumed,
26364 			lastLeaf,
26365 			currentState,
26366 			dot = 14;	// special transition which matches all characters. See AreaCodeTableMaker.java
26367 
26368 		if (!number || !stateTable) {
26369 			// can't parse anything
26370 			return undefined;
26371 		}
26372 
26373 		//console.log("GeoLocator._parseAreaAndSubscriber: parsing number " + number);
26374 
26375 		currentState = stateTable;
26376 		i = 0;
26377 		while (i < number.length) {
26378 			ch = ilib.PhoneNumber._getCharacterCode(number.charAt(i));
26379 			if (ch >= 0) {
26380 				// newState = stateData.states[state][ch];
26381 				newState = currentState.s && currentState.s[ch];
26382 				
26383 				if (!newState && currentState.s && currentState.s[dot]) {
26384 					newState = currentState.s[dot];
26385 				}
26386 				
26387 				if (typeof(newState) === 'object') {
26388 					if (typeof(newState.l) !== 'undefined') {
26389 						// save for latter if needed
26390 						lastLeaf = newState;
26391 						consumed = i;
26392 					}
26393 					// console.info("recognized digit " + ch + " continuing...");
26394 					// recognized digit, so continue parsing
26395 					currentState = newState;
26396 					i++;
26397 				} else {
26398 					if (typeof(newState) === 'undefined' || newState === 0) {
26399 						// this is possibly a look-ahead and it didn't work... 
26400 						// so fall back to the last leaf and use that as the
26401 						// final state
26402 						newState = lastLeaf;
26403 						i = consumed;
26404 					}
26405 					
26406 					if ((typeof(newState) === 'number' && newState) ||
26407 						(typeof(newState) === 'object' && typeof(newState.l) !== 'undefined')) {
26408 						// final state
26409 						var stateNumber = typeof(newState) === 'number' ? newState : newState.l;
26410 						handlerMethod = ilib.PhoneNumber._states[stateNumber];
26411 
26412 						//console.info("reached final state " + newState + " handler method is " + handlerMethod + " and i is " + i);
26413 	
26414 						return (handlerMethod === "area") ? number.substring(0, i+1) : undefined;
26415 					} else {
26416 						// failed parse. Either no last leaf to fall back to, or there was an explicit
26417 						// zero in the table
26418 						break;
26419 					}
26420 				}
26421 			} else if (ch === -1) {
26422 				// non-transition character, continue parsing in the same state
26423 				i++;
26424 			} else {
26425 				// should not happen
26426 				// console.info("skipping character " + ch);
26427 				// not a digit, plus, pound, or star, so this is probably a formatting char. Skip it.
26428 				i++;
26429 			}
26430 		}
26431 		return undefined;
26432 	},
26433 	/**
26434 	 * @private
26435 	 * @param prefix
26436 	 * @param table
26437 	 * @returns
26438 	 */
26439 	_matchPrefix: function(prefix, table)  {
26440 		var i, matchedDot, matchesWithDots = [];
26441 
26442 		if (table[prefix]) {
26443 			return table[prefix];
26444 		}
26445 		for (var entry in table) {
26446 			if (entry && typeof(entry) === 'string') {
26447 				i = 0;
26448 				matchedDot = false;
26449 				while (i < entry.length && (entry.charAt(i) === prefix.charAt(i) || entry.charAt(i) === '.')) {
26450 					if (entry.charAt(i) === '.') {
26451 						matchedDot = true;
26452 					}
26453 					i++;
26454 				}
26455 				if (i >= entry.length) {
26456 					if (matchedDot) {
26457 						matchesWithDots.push(entry);
26458 					} else {
26459 						return table[entry];
26460 					}
26461 				}
26462 			}
26463 		}
26464 
26465 		// match entries with dots last, so sort the matches so that the entry with the 
26466 		// most dots sorts last. The entry that ends up at the beginning of the list is
26467 		// the best match because it has the fewest dots
26468 		if (matchesWithDots.length > 0) {
26469 			matchesWithDots.sort(function (left, right) {
26470 				return (right < left) ? -1 : ((left < right) ? 1 : 0);
26471 			});
26472 			return table[matchesWithDots[0]];
26473 		}
26474 		
26475 		return undefined;
26476 	},
26477 	/**
26478 	 * @private
26479 	 * @param number
26480 	 * @param data
26481 	 * @param locale
26482 	 * @param plan
26483 	 * @param options
26484 	 * @returns {Object}
26485 	 */
26486 	_getAreaInfo: function(number, data, locale, plan, options) {
26487 		var sync = true,
26488 			ret = {}, 
26489 			countryCode, 
26490 			areaInfo, 
26491 			temp, 
26492 			areaCode, 
26493 			geoTable, 
26494 			tempNumber, 
26495 			prefix;
26496 
26497 		if (options && typeof(options.sync) === 'boolean') {
26498 			sync = options.sync;
26499 		}
26500 
26501 		prefix = number.areaCode || number.serviceCode;
26502 		geoTable = data;
26503 		
26504 		if (prefix !== undefined) {
26505 			if (plan.getExtendedAreaCode()) {
26506 				// for countries where the area code is very general and large, and you need a few initial
26507 				// digits of the subscriber number in order find the actual area
26508 				tempNumber = prefix + number.subscriberNumber;
26509 				tempNumber = tempNumber.replace(/[wWpPtT\+#\*]/g, '');	// fix for NOV-108200
26510 		
26511 				ilib.loadData({
26512 					name: "extarea.json",
26513 					object: ilib.GeoLocator, 
26514 					locale: locale,
26515 					sync: sync,
26516 					loadParams: ilib.merge((options && options.loadParams) || {}, {returnOne: true}),
26517 					callback: ilib.bind(this, function (data) {
26518 						this.extarea = data;
26519 						ilib.loadData({
26520 							name: "extstates.json",
26521 							object: ilib.GeoLocator, 
26522 							locale: locale,
26523 							sync: sync,
26524 							loadParams: ilib.merge((options && options.loadParams) || {}, {returnOne: true}),
26525 							callback: ilib.bind(this, function (data) {
26526 								this.extstates = data;
26527 								geoTable = this.extarea;
26528 								if (this.extarea && this.extstates) {
26529 									prefix = this._parseAreaAndSubscriber(tempNumber, this.extstates);
26530 								}
26531 								
26532 								if (!prefix) {
26533 									// not a recognized prefix, so now try the general table
26534 									geoTable = this.areadata;
26535 									prefix = number.areaCode || number.serviceCode;					
26536 								}
26537 
26538 								if ((!plan.fieldLengths || 
26539 								  plan.getFieldLength('maxLocalLength') === undefined ||
26540 								  !number.subscriberNumber ||
26541 								 	number.subscriberNumber.length <= plan.fieldLengths('maxLocalLength'))) {
26542 								  	areaInfo = this._matchPrefix(prefix, geoTable);
26543 									if (areaInfo && areaInfo.sn && areaInfo.ln) {
26544 										//console.log("Found areaInfo " + JSON.stringify(areaInfo));
26545 										ret.area = {
26546 											sn: this.rb.getString(areaInfo.sn).toString(),
26547 											ln: this.rb.getString(areaInfo.ln).toString()
26548 										};
26549 									}
26550 								}		
26551 							})
26552 						});
26553 					})
26554 				});
26555 
26556 			} else if (!plan || 
26557 					plan.getFieldLength('maxLocalLength') === undefined || 
26558 					!number.subscriberNumber ||
26559 					number.subscriberNumber.length <= plan.getFieldLength('maxLocalLength')) {
26560 				if (geoTable) {
26561 					areaCode = prefix.replace(/[wWpPtT\+#\*]/g, '');
26562 					areaInfo = this._matchPrefix(areaCode, geoTable);
26563 
26564 					if (areaInfo && areaInfo.sn && areaInfo.ln) {
26565 						ret.area = {
26566 							sn: this.rb.getString(areaInfo.sn).toString(),
26567 							ln: this.rb.getString(areaInfo.ln).toString()
26568 						};
26569 					} else if (number.serviceCode) {
26570 						ret.area = {
26571 							sn: this.rb.getString("Service Number").toString(),
26572 							ln: this.rb.getString("Service Number").toString()
26573 						};
26574 					}
26575 				} else {
26576 					countryCode = number.locale._mapRegiontoCC(this.locale.getRegion());
26577 					if (countryCode !== "0" && this.regiondata) {
26578 						temp = this.regiondata[countryCode];
26579 						if (temp && temp.sn) {
26580 							ret.country = {
26581 								sn: this.rb.getString(temp.sn).toString(),
26582 								ln: this.rb.getString(temp.ln).toString(),
26583 								code: this.locale.getRegion()
26584 							};
26585 						}
26586 					}
26587 				}
26588 			} else {
26589 				countryCode = number.locale._mapRegiontoCC(this.locale.getRegion());
26590 				if (countryCode !== "0" && this.regiondata) {
26591 					temp = this.regiondata[countryCode];
26592 					if (temp && temp.sn) {
26593 						ret.country = {
26594 							sn: this.rb.getString(temp.sn).toString(),
26595 							ln: this.rb.getString(temp.ln).toString(),
26596 							code: this.locale.getRegion()
26597 						};
26598 					}
26599 				}
26600 			}
26601 
26602 		} else if (number.mobilePrefix) {
26603 			ret.area = {
26604 				sn: this.rb.getString("Mobile Number").toString(),
26605 				ln: this.rb.getString("Mobile Number").toString()
26606 			};
26607 		} else if (number.emergency) {
26608 			ret.area = {
26609 				sn: this.rb.getString("Emergency Services Number").toString(),
26610 				ln: this.rb.getString("Emergency Services Number").toString()
26611 			};
26612 		}
26613 
26614 		return ret;
26615 	},
26616 	/**
26617 	 * Returns a the location of the given phone number, if known. 
26618 	 * The returned object has 2 properties, each of which has an sn (short name) 
26619 	 * and an ln (long name) string. Additionally, the country code, if given,
26620 	 * includes the 2 letter ISO code for the recognized country.
26621 	 *	 	{
26622 	 *			"country": {
26623 	 *	        	"sn": "North America",
26624 	 *            	"ln": "North America and the Caribbean Islands",
26625 	 *				"code": "us"
26626 	 *         	 },
26627 	 *         	 "area": {
26628 	 *       	    "sn": "California",
26629 	 *          	 "ln": "Central California: San Jose, Los Gatos, Milpitas, Sunnyvale, Cupertino, Gilroy"
26630 	 *         	 }
26631 	 *    	 }
26632 	 * 
26633 	 * The location name is subject to the following rules:
26634 	 *
26635 	 * If the areaCode property is undefined or empty, or if the number specifies a 
26636 	 * country code for which we do not have information, then the area property may be 
26637 	 * missing from the returned object. In this case, only the country object will be returned.
26638 	 *
26639 	 * If there is no area code, but there is a mobile prefix, service code, or emergency 
26640 	 * code, then a fixed string indicating the type of number will be returned.
26641 	 * 
26642 	 * The country object is filled out according to the countryCode property of the phone
26643 	 * number. 
26644 	 * 
26645 	 * If the phone number does not have an explicit country code, the MCC will be used if
26646 	 * it is available. The country code can be gleaned directly from the MCC. If the MCC 
26647 	 * of the carrier to which the phone is currently connected is available, it should be 
26648 	 * passed in so that local phone numbers will look correct.
26649 	 * 
26650 	 * If the country's dialling plan mandates a fixed length for phone numbers, and a 
26651 	 * particular number exceeds that length, then the area code will not be given on the
26652 	 * assumption that the number has problems in the first place and we cannot guess
26653 	 * correctly.
26654 	 *
26655 	 * The returned area property varies in specificity according
26656 	 * to the locale. In North America, the area is no finer than large parts of states
26657 	 * or provinces. In Germany and the UK, the area can be as fine as small towns.
26658 	 *
26659 	 * The strings returned from this function are already localized to the 
26660 	 * given locale, and thus are ready for display to the user.
26661 	 *
26662 	 * If the number passed in is invalid, an empty object is returned. If the location
26663 	 * information about the country where the phone number is located is not available,
26664 	 * then the area information will be missing and only the country will be returned.
26665      *
26666 	 * The options parameter can contain any one of the following properties:
26667  	 * 
26668  	 * <ul>
26669  	 * <li><i>locale</i> The locale parameter is used to load translations of the names of regions and
26670  	 * areas if available. For example, if the locale property is given as "en-US" (English for USA), 
26671  	 * but the phone number being geolocated is in Germany, then this class would return the the names
26672  	 * of the country (Germany) and region inside of Germany in English instead of German. That is, a 
26673  	 * phone number in Munich and return the country "Germany" and the area code "Munich"
26674  	 * instead of "Deutschland" and "München". The default display locale is the current ilib locale. 
26675  	 * If translations are not available, the region and area names are given in English, which should 
26676  	 * always be available.
26677  	 * <li><i>mcc</i> The mcc of the current mobile carrier, if known.
26678  	 * 
26679  	 * <li><i>onLoad</i> - a callback function to call when the data for the
26680  	 * locale is fully loaded. When the onLoad option is given, this object 
26681  	 * will attempt to load any missing locale data using the ilib loader callback.
26682  	 * When the constructor is done (even if the data is already preassembled), the 
26683  	 * onLoad function is called with the current instance as a parameter, so this
26684  	 * callback can be used with preassembled or dynamic loading or a mix of the two. 
26685  	 * 
26686  	 * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
26687  	 * asynchronously. If this option is given as "false", then the "onLoad"
26688  	 * callback must be given, as the instance returned from this constructor will
26689  	 * not be usable for a while. 
26690  	 *
26691  	 * <li><i>loadParams</i> - an object containing parameters to pass to the 
26692  	 * loader callback function when locale data is missing. The parameters are not
26693  	 * interpretted or modified in any way. They are simply passed along. The object 
26694  	 * may contain any property/value pairs as long as the calling code is in
26695  	 * agreement with the loader callback function as to what those parameters mean.
26696  	 * </ul>
26697 	 * 
26698 	 * @param {ilib.PhoneNumber} number phone number to locate
26699 	 * @param {Object} options options governing the way this ares is loaded
26700 	 * @return {Object} an object  
26701 	 * that describes the country and the area in that country corresponding to this
26702 	 * phone number. Each of the country and area contain a short name (sn) and long
26703 	 * name (ln) that describes the location.
26704 	 */
26705 	locate: function(number, options) {
26706 		var loadParams = {},
26707 			ret = {}, 
26708 			region, 
26709 			countryCode, 
26710 			temp, 
26711 			plan,
26712 			areaResult,
26713 			phoneLoc = this.locale,
26714 			sync = true;
26715 
26716 		if (number === undefined || typeof(number) !== 'object' || !(number instanceof ilib.PhoneNumber)) {
26717 			return ret;
26718 		}
26719 
26720 		if (options) {
26721 			if (typeof(options.sync) !== 'undefined') {
26722 				sync = (options.sync == true);
26723 			}
26724 		
26725 			if (options.loadParams) {
26726 				loadParams = options.loadParams;
26727 			}
26728 		}
26729 
26730 		// console.log("GeoLocator.locate: looking for geo for number " + JSON.stringify(number));
26731 		region = this.locale.getRegion();
26732 		if (number.countryCode !== undefined && this.regiondata) {
26733 			countryCode = number.countryCode.replace(/[wWpPtT\+#\*]/g, '');
26734 			temp = this.regiondata[countryCode];
26735 			phoneLoc = number.destinationLocale;
26736 			plan = number.destinationPlan;
26737 			ret.country = {
26738 				sn: this.rb.getString(temp.sn).toString(),
26739 				ln: this.rb.getString(temp.ln).toString(),
26740 				code: phoneLoc.getRegion()
26741 			};
26742 		}
26743 		
26744 		if (!plan) {
26745 			plan = this.plan;
26746 		}
26747 		
26748 		ilib.loadData({
26749 			name: "area.json",
26750 			object: ilib.GeoLocator,
26751 			locale: phoneLoc,
26752 			sync: sync,
26753 			loadParams: ilib.merge(loadParams, {
26754 				returnOne: true
26755 			}),
26756 			callback: ilib.bind(this, function (areadata) {
26757 				if (areadata) {
26758 					this.areadata = areadata;	
26759 				}
26760 				areaResult = this._getAreaInfo(number, this.areadata, phoneLoc, plan, options);
26761 				ret = ilib.merge(ret, areaResult);
26762 
26763 				if (ret.country === undefined) {
26764 					countryCode = number.locale._mapRegiontoCC(region);
26765 					
26766 					if (countryCode !== "0" && this.regiondata) {
26767 						temp = this.regiondata[countryCode];
26768 						if (temp && temp.sn) {
26769 							ret.country = {
26770 								sn: this.rb.getString(temp.sn).toString(),
26771 								ln: this.rb.getString(temp.ln).toString(),
26772 								code: this.locale.getRegion()
26773 							};
26774 						}
26775 					}
26776 				}
26777 			})
26778 		});
26779 		
26780 		return ret;
26781 	},
26782 	
26783 	/**
26784 	 * Returns a string that describes the ISO-3166-2 country code of the given phone
26785 	 * number.<p> 
26786 	 * 
26787 	 * If the phone number is a local phone number and does not contain
26788 	 * any country information, this routine will return the region for the current
26789 	 * formatter instance.
26790      *
26791 	 * @param {ilib.PhoneNumber} number An ilib.PhoneNumber instance
26792 	 * @return {string}
26793 	 */
26794 	country: function(number) {
26795 		var countryCode,
26796 			region,
26797 			phoneLoc;
26798 
26799 		if (!number || !(number instanceof ilib.PhoneNumber)) {
26800 			return "";
26801 		}
26802 
26803 		phoneLoc = number.locale;
26804 
26805 		region = (number.countryCode && phoneLoc._mapCCtoRegion(number.countryCode)) ||
26806 			(number.locale && number.locale.region) || 
26807 			phoneLoc.locale.getRegion() ||
26808 			this.locale.getRegion();
26809 
26810 		countryCode = number.countryCode || phoneLoc._mapRegiontoCC(region);
26811 		
26812 		if (number.areaCode) {
26813 			region = phoneLoc._mapAreatoRegion(countryCode, number.areaCode);
26814 		} else if (countryCode === "33" && number.serviceCode) {
26815 			// french departments are in the service code, not the area code
26816 			region = phoneLoc._mapAreatoRegion(countryCode, number.serviceCode);
26817 		}		
26818 		return region;
26819 	}
26820 };
26821 /*
26822  * unit.js - Unit class
26823  * 
26824  * Copyright © 2014, JEDLSoft
26825  *
26826  * Licensed under the Apache License, Version 2.0 (the "License");
26827  * you may not use this file except in compliance with the License.
26828  * You may obtain a copy of the License at
26829  *
26830  *     http://www.apache.org/licenses/LICENSE-2.0
26831  *
26832  * Unless required by applicable law or agreed to in writing, software
26833  * distributed under the License is distributed on an "AS IS" BASIS,
26834  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26835  *
26836  * See the License for the specific language governing permissions and
26837  * limitations under the License.
26838  */
26839 
26840 /*
26841 !depends 
26842 ilibglobal.js 
26843 locale.js 
26844 localeinfo.js
26845 */
26846 
26847 
26848 /**
26849  * @class
26850  * Create a measurement instance. The measurement is immutable once
26851  * it is created, but can be converted to other measurements later.<p>
26852  * 
26853  * The options may contain any of the following properties:
26854  * 
26855  * <ul>
26856  * <li><i>amount</i> - either a numeric amount for this measurement given
26857  * as a number of the specified units, or another ilib.Measurement instance 
26858  * to convert to the requested units. If converting to new units, the type
26859  * of measure between the other instance's units and the current units
26860  * must be the same. That is, you can only convert one unit of mass to
26861  * another. You cannot convert a unit of mass into a unit of length. 
26862  * 
26863  * <li><i>unit</i> - units of this measurement. Use the 
26864  * static call {@link ilib.Measurement.getAvailableUnits}
26865  * to find out what units this version of ilib supports. If the given unit
26866  * is not a base unit, the amount will be normalized to the number of base units
26867  * and stored as that number of base units.
26868  * For example, if an instance is constructed with 1 kg, this will be converted
26869  * automatically into 1000 g, as grams are the base unit and kg is merely a 
26870  * commonly used scale of grams.
26871  * </ul>
26872  * 
26873  * Here are some examples of converting a length into new units. The first method
26874  * is via the constructor by passing the old measurement in as the amount property.
26875  * 
26876  * <pre>
26877  * var measurement1 = new ilib.Measurement({
26878  *   amount: 5,
26879  *   units: "kilometers"
26880  * });
26881  * var measurement2 = new ilib.Measurement({
26882  *   amount: measurement1,
26883  *   units: "miles"
26884  * });
26885  * </pre>
26886  * 
26887  * The value in measurement2 will end up being about 3.125 miles.
26888  * 
26889  * The second method will be using the convert method.
26890  * 
26891  * <pre>
26892  * var measurement1 = new ilib.Measurement({
26893  *   amount: 5,
26894  *   units: "kilometers"
26895  * });
26896  * var measurement2 = measurement1.convert("miles");
26897  * });
26898  * </pre>
26899  *
26900  * The value in measurement2 will again end up being about 3.125 miles.
26901  * 
26902  * @constructor 
26903  * @param {Object} options options that control the construction of this instance
26904  */
26905 ilib.Measurement = function(options) {
26906 	if (!options || typeof(options.unit) === 'undefined') {
26907 		return undefined;
26908 	}
26909 
26910 	this.amount = options.amount || 0;
26911 	var measure = undefined;
26912 
26913 	for (var c in ilib.Measurement._constructors) {
26914 		var measurement = ilib.Measurement._constructors[c];
26915 		if (typeof(measurement.aliases[options.unit]) !== 'undefined') {
26916 			measure = c;
26917 			break;
26918 		}
26919 	}
26920 
26921 	if (!measure || typeof(measure) === 'undefined') {
26922 		return new ilib.Measurement.Unknown({
26923 			unit: options.unit,
26924 			amount: options.amount
26925 		});                
26926 	} else {
26927 		return new ilib.Measurement._constructors[measure](options);
26928 	}
26929 };
26930 
26931 /**
26932  * @private
26933  */
26934 ilib.Measurement._constructors = {};
26935 
26936 /**
26937  * Return a list of all possible units that this version of ilib supports.
26938  * Typically, the units are given as their full names in English. Unit names
26939  * are case-insensitive.
26940  * 
26941  * @static
26942  * @return {Array.<string>} an array of strings containing names of units available
26943  */
26944 ilib.Measurement.getAvailableUnits = function () {
26945 	var units = [];
26946 	for (var c in ilib.Measurement._constructors) {
26947 		var measure = ilib.Measurement._constructors[c];
26948 		units = units.concat(measure.getMeasures());
26949 	}
26950 	return units;
26951 };
26952 
26953 ilib.Measurement.metricScales = {
26954 	"femto": {"symbol": "f", "scale": -15},
26955 	"pico": {"symbol": "p", "scale": -12},
26956 	"nano": {"symbol": "n", "scale": -9},
26957 	"micro": {"symbol": "µ", "scale": -6},
26958 	"milli": {"symbol": "m", "scale": -3},
26959 	"centi": {"symbol": "c", "scale": -2},
26960 	"deci": {"symbol": "d", "scale": -1},
26961 	"deca": {"symbol": "da", "scale": 1},
26962 	"hecto": {"symbol": "h", "scale": 2},
26963 	"kilo": {"symbol": "k", "scale": 3},
26964 	"mega": {"symbol": "M", "scale": 6},
26965 	"giga": {"symbol": "G", "scale": 9},
26966 	"peta": {"symbol": "P", "scale": 12},
26967 	"exa": {"symbol": "E", "scale": 18}
26968 };
26969 
26970 ilib.Measurement.prototype = {
26971 	/**
26972 	 * Return the normalized name of the given units. If the units are
26973 	 * not recognized, this method returns its parameter unmodified.<p>
26974 	 * 
26975 	 * Examples:
26976 	 * 
26977 	 * <ui>
26978 	 * <li>"metres" gets normalized to "meter"<br>
26979 	 * <li>"ml" gets normalized to "milliliter"<br>
26980 	 * <li>"foobar" gets normalized to "foobar" (no change because it is not recognized)
26981 	 * </ul>
26982 	 *  
26983 	 * @param {string} name name of the units to normalize. 
26984 	 * @returns {string} normalized name of the units
26985 	 */
26986 	normalizeUnits: function(name) {
26987 		return this.aliases[name] || name;
26988 	},
26989 
26990 	/**
26991 	 * Return the normalized units used in this measurement.
26992 	 * @return {string} name of the unit of measurement 
26993 	 */
26994 	getUnit: function() {
26995 		return this.unit;
26996 	},
26997      
26998 	/**
26999 	 * Return the units originally used to construct this measurement
27000 	 * before it was normalized.
27001 	 * @return {string} name of the unit of measurement 
27002 	 */
27003 	getOriginalUnit: function() {
27004 		return this.originalUnit;
27005 	},
27006 	
27007 	/**
27008 	 * Return the numeric amount of this measurement.
27009 	 * @return {number} the numeric amount of this measurement
27010 	 */
27011 	getAmount: function() {
27012 		return this.amount;
27013 	},
27014 	
27015 	/**
27016 	 * Return the type of this measurement. Examples are "mass",
27017 	 * "length", "speed", etc. Measurements can only be converted
27018 	 * to measurements of the same type.<p>
27019 	 * 
27020 	 * The type of the units is determined automatically from the 
27021 	 * units. For example, the unit "grams" is type "mass". Use the 
27022 	 * static call {@link ilib.Measurement.getAvailableUnits}
27023 	 * to find out what units this version of ilib supports.
27024 	 * 
27025 	 * @abstract
27026 	 * @return {string} the name of the type of this measurement
27027 	 */
27028 	getMeasure: function() {},
27029 	
27030 	/**
27031 	 * Return a new measurement instance that is converted to a new
27032 	 * measurement unit. Measurements can only be converted
27033 	 * to measurements of the same type.<p>
27034 	 * 
27035 	 * @abstract
27036 	 * @param {string} to The name of the units to convert to
27037 	 * @return {ilib.Measurement|undefined} the converted measurement
27038 	 * or undefined if the requested units are for a different
27039 	 * measurement type
27040 	 */
27041 	convert: function(to) {},     
27042         
27043         /**
27044 	 * Scale the measurement unit to an acceptable level. The scaling
27045 	 * happens so that the integer part of the amount is as small as
27046 	 * possible without being below zero. This will result in the 
27047 	 * largest units that can represent this measurement without
27048 	 * fractions. Measurements can only be scaled to other measurements 
27049 	 * of the same type.
27050 	 * 
27051 	 * @abstract
27052 	 * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
27053 	 * or undefined if the system can be inferred from the current measure
27054 	 * @return {ilib.Measurement} a new instance that is scaled to the 
27055 	 * right level
27056 	 */
27057 	scale: function(measurementsystem) {},
27058         
27059 	/**
27060 	 * Localize the measurement to the commonly used measurement in that locale, for example
27061 	 * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
27062 	 * the formatted number should be automatically converted to the most appropriate 
27063 	 * measure in the other system, in this case, mph. The formatted result should
27064 	 * appear as "37.3 mph". 
27065 	 * 
27066 	 * @abstract
27067 	 * @param {string} locale current locale string
27068 	 * @returns {ilib.Measurement} a new instance that is converted to locale
27069 	 */
27070 	localize: function(locale) {}
27071 };
27072 
27073 /*
27074  * unitfmt.js - Unit formatter class
27075  * 
27076  * Copyright © 2014, JEDLSoft
27077  *
27078  * Licensed under the Apache License, Version 2.0 (the "License");
27079  * you may not use this file except in compliance with the License.
27080  * You may obtain a copy of the License at
27081  *
27082  *     http://www.apache.org/licenses/LICENSE-2.0
27083  *
27084  * Unless required by applicable law or agreed to in writing, software
27085  * distributed under the License is distributed on an "AS IS" BASIS,
27086  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27087  *
27088  * See the License for the specific language governing permissions and
27089  * limitations under the License.
27090  */
27091 
27092 /*
27093 !depends 
27094 ilibglobal.js 
27095 locale.js 
27096 resources.js 
27097 localeinfo.js
27098 strings.js
27099 */
27100 
27101 // !data unitfmt
27102 
27103 /**
27104  * @class
27105  * Create a new unit formatter instance. The unit formatter is immutable once
27106  * it is created, but can format as many different strings with different values
27107  * as needed with the same options. Create different unit formatter instances 
27108  * for different purposes and then keep them cached for use later if you have 
27109  * more than one unit string to format.<p>
27110  * 
27111  * The options may contain any of the following properties:
27112  * 
27113  * <ul>
27114  * <li><i>locale</i> - locale to use when formatting the units. The locale also
27115  * controls the translation of the names of the units. If the locale is
27116  * not specified, then the default locale of the app or web page will be used.
27117  * 
27118  * <li><i>autoScale</i> - when true, automatically scale the amount to get the smallest
27119  * number greater than 1, where possible, possibly by converting units within the locale's
27120  * measurement system. For example, if the current locale is "en-US", and we have
27121  * a measurement containing 278 fluid ounces, then the number "278" can be scaled down
27122  * by converting the units to a larger one such as gallons. The scaled size would be
27123  * 2.17188 gallons. Since iLib does not have a US customary measure larger than gallons,
27124  * it cannot scale it down any further. If the amount is less than the smallest measure
27125  * already, it cannot be scaled down any further and no autoscaling will be applied.
27126  * Default for the autoScale property is "true", so it only needs to be specified when
27127  * you want to turn off autoscaling.
27128  * 
27129  * <li><i>autoConvert</i> - automatically convert the units to the nearest appropriate
27130  * measure of the same type in the measurement system used by the locale. For example, 
27131  * if a measurement of length is given in meters, but the current locale is "en-US" 
27132  * which uses the US Customary system, then the nearest appropriate measure would be 
27133  * "yards", and the amount would be converted from meters to yards automatically before
27134  * being formatted. Default for the autoConvert property is "true", so it only needs to 
27135  * be specified when you want to turn off autoconversion.
27136  * 
27137  * <li><i>maxFractionDigits</i> - the maximum number of digits that should appear in the
27138  * formatted output after the decimal. A value of -1 means unlimited, and 0 means only print
27139  * the integral part of the number.
27140  * 
27141  * <li><i>minFractionDigits</i> - the minimum number of fractional digits that should
27142  * appear in the formatted output. If the number does not have enough fractional digits
27143  * to reach this minimum, the number will be zero-padded at the end to get to the limit.
27144  * 
27145  * <li><i>roundingMode</i> - When the maxFractionDigits or maxIntegerDigits is specified,
27146  * this property governs how the least significant digits are rounded to conform to that
27147  * maximum. The value of this property is a string with one of the following values:
27148  * <ul>
27149  *   <li><i>up</i> - round away from zero
27150  *   <li><i>down</i> - round towards zero. This has the effect of truncating the number
27151  *   <li><i>ceiling</i> - round towards positive infinity
27152  *   <li><i>floor</i> - round towards negative infinity
27153  *   <li><i>halfup</i> - round towards nearest neighbour. If equidistant, round up.
27154  *   <li><i>halfdown</i> - round towards nearest neighbour. If equidistant, round down.
27155  *   <li><i>halfeven</i> - round towards nearest neighbour. If equidistant, round towards the even neighbour
27156  *   <li><i>halfodd</i> - round towards nearest neighbour. If equidistant, round towards the odd neighbour
27157  * </ul>
27158  * 
27159  * <li><i>onLoad</i> - a callback function to call when the date format object is fully 
27160  * loaded. When the onLoad option is given, the UnitFmt object will attempt to
27161  * load any missing locale data using the ilib loader callback.
27162  * When the constructor is done (even if the data is already preassembled), the 
27163  * onLoad function is called with the current instance as a parameter, so this
27164  * callback can be used with preassembled or dynamic loading or a mix of the two.
27165  * 
27166  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
27167  * asynchronously. If this option is given as "false", then the "onLoad"
27168  * callback must be given, as the instance returned from this constructor will
27169  * not be usable for a while.
27170  *  
27171  * <li><i>loadParams</i> - an object containing parameters to pass to the 
27172  * loader callback function when locale data is missing. The parameters are not
27173  * interpretted or modified in any way. They are simply passed along. The object 
27174  * may contain any property/value pairs as long as the calling code is in
27175  * agreement with the loader callback function as to what those parameters mean.
27176  * </ul>
27177  * 
27178  * Here is an example of how you might use the unit formatter to format a string with
27179  * the correct units.<p>
27180  * 
27181  * Depends directive: !depends unitfmt.js
27182  *  
27183  * @constructor
27184  * @param {Object} options options governing the way this date formatter instance works
27185  */
27186 ilib.UnitFmt = function(options) {
27187 	var sync = true, 
27188 		loadParams = undefined;
27189 	
27190     this.length = "long";
27191     this.scale  = true;
27192     this.measurementType = 'undefined';
27193     this.convert = true;
27194 	this.locale = new ilib.Locale();
27195 
27196     if (options) {
27197     	if (options.locale) {
27198     		this.locale = (typeof(options.locale) === 'string') ? new ilib.Locale(options.locale) : options.locale;
27199     	}
27200 
27201     	if (typeof(options.sync) === 'boolean') {
27202     		sync = options.sync;
27203     	}
27204 
27205     	if (typeof(options.loadParams) !== 'undefined') {
27206     		loadParams = options.loadParams;
27207     	}
27208 
27209     	if (options.length) {
27210     		this.length = options.length;
27211     	}
27212 
27213     	if (typeof(options.autoScale) === 'boolean') {
27214     		this.scale = options.autoScale;
27215     	}
27216 
27217     	if (typeof(options.autoConvert) === 'boolean') {
27218     		this.convert = options.autoConvert;
27219     	}
27220         
27221         if (typeof(options.useNative) === 'boolean') {
27222     		this.useNative = options.useNative;
27223     	}
27224 
27225     	if (options.measurementSystem) {
27226     		this.measurementSystem = options.measurementSystem;
27227     	}
27228         
27229         if (typeof (options.maxFractionDigits) === 'number') {
27230             /** 
27231              * @private
27232              * @type {number|undefined} 
27233              */
27234             this.maxFractionDigits = options.maxFractionDigits;
27235         }
27236         if (typeof (options.minFractionDigits) === 'number') {
27237             /** 
27238              * @private
27239              * @type {number|undefined} 
27240              */
27241             this.minFractionDigits = options.minFractionDigits;
27242         }
27243         /** 
27244          * @private
27245          * @type {string} 
27246          */
27247         this.roundingMode = options.roundingMode;
27248     }
27249 
27250     if (!ilib.UnitFmt.cache) {
27251     	ilib.UnitFmt.cache = {};
27252     }
27253 
27254 	ilib.loadData({
27255 		object: ilib.UnitFmt, 
27256 		locale: this.locale, 
27257 		name: "unitfmt.json", 
27258 		sync: sync, 
27259 		loadParams: loadParams, 
27260 		callback: ilib.bind(this, function (format) {                      
27261 			var formatted = format;
27262 			this.template = formatted["unitfmt"][this.length];
27263 			if (options && typeof(options.onLoad) === 'function') {
27264 				options.onLoad(this);
27265 			}
27266 		})
27267 	});
27268 };
27269 
27270 ilib.UnitFmt.prototype = {
27271 	
27272 	/**
27273 	 * Return the locale used with this formatter instance.
27274 	 * @return {ilib.Locale} the ilib.Locale instance for this formatter
27275 	 */
27276 	getLocale: function() {
27277 		return this.locale;
27278 	},
27279 	
27280 	/**
27281 	 * Return the template string that is used to format date/times for this
27282 	 * formatter instance. This will work, even when the template property is not explicitly 
27283 	 * given in the options to the constructor. Without the template option, the constructor 
27284 	 * will build the appropriate template according to the options and use that template
27285 	 * in the format method. 
27286 	 * 
27287 	 * @return {string} the format template for this formatter
27288 	 */
27289 	getTemplate: function() {
27290 		return this.template;
27291 	},
27292 	
27293 	/**
27294 	 * Convert this formatter to a string representation by returning the
27295 	 * format template. This method delegates to getTemplate.
27296 	 * 
27297 	 * @return {string} the format template
27298 	 */
27299 	toString: function() {
27300 		return this.getTemplate();
27301 	},
27302     
27303 	/**
27304 	 * Return whether or not this formatter will auto-scale the units while formatting.
27305 	 * @returns {boolean} true if auto-scaling is turned on
27306 	 */
27307     getScale: function() {
27308         return this.scale;
27309     },
27310 
27311     /**
27312      * Return the measurement system that is used for this formatter.
27313      * @returns {string} the measurement system used in this formatter
27314      */
27315     getMeasurementSystem: function() {
27316         return this.measurementSystem;
27317     },
27318 
27319 	/**
27320 	 * Format a particular unit instance according to the settings of this
27321 	 * formatter object.
27322 	 * 
27323 	 * @param {ilib.Measurement} measurement measurement to format	 
27324 	 * @return {string} the formatted version of the given date instance
27325 	 */
27326     format: function (measurement) {
27327     	var u = this.convert ? measurement.localize(this.locale.getSpec()) : measurement;
27328     	u = this.scale ? u.scale(this.measurementSystem) : u;
27329     	var formatted = new ilib.String(this.template[u.getUnit()]);
27330     	// make sure to use the right plural rules
27331     	formatted.setLocale(this.locale, true, undefined, undefined);
27332     	var numFmt = new ilib.NumFmt({
27333     		locale: this.locale,
27334     		useNative: this.useNative,
27335             maxFractionDigits: this.maxFractionDigits,
27336             minFractionDigits: this.minFractionDigits,
27337             roundingMode: this.roundingMode
27338     	});
27339     	formatted = formatted.formatChoice(u.amount,{n:numFmt.format(u.amount)});
27340     	return formatted.length > 0 ? formatted : u.amount +" " + u.unit;
27341     }
27342 };
27343 
27344 /*
27345  * Length.js - Unit conversions for Lengths/lengths
27346  * 
27347  * Copyright © 2014, JEDLSoft
27348  *
27349  * Licensed under the Apache License, Version 2.0 (the "License");
27350  * you may not use this file except in compliance with the License.
27351  * You may obtain a copy of the License at
27352  *
27353  *     http://www.apache.org/licenses/LICENSE-2.0
27354  *
27355  * Unless required by applicable law or agreed to in writing, software
27356  * distributed under the License is distributed on an "AS IS" BASIS,
27357  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27358  *
27359  * See the License for the specific language governing permissions and
27360  * limitations under the License.
27361  */
27362 
27363 /*
27364 !depends 
27365 ilibglobal.js 
27366 */
27367 
27368 /**
27369  * @class
27370  * Create a new length measurement instance.
27371  *  
27372  * @constructor
27373  * @extends ilib.Measurement
27374  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
27375  * the construction of this instance
27376  */
27377 ilib.Measurement.Length = function (options) {
27378 	this.unit = "meter";
27379 	this.amount = 0;
27380 	this.aliases = ilib.Measurement.Length.aliases; // share this table in all instances
27381 	
27382 	if (options) {
27383 		if (typeof(options.unit) !== 'undefined') {
27384 			this.originalUnit = options.unit;
27385 			this.unit = this.aliases[options.unit] || options.unit;
27386 		}
27387 		
27388 		if (typeof(options.amount) === 'object') {
27389 			if (options.amount.getMeasure() === "length") {
27390 				this.amount = ilib.Measurement.Length.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
27391 			} else {
27392 				throw "Cannot convert unit " + options.amount.unit + " to a length";
27393 			}
27394 		} else if (typeof(options.amount) !== 'undefined') {
27395 			this.amount = parseFloat(options.amount);
27396 		}
27397 	}
27398 	
27399 	if (typeof(ilib.Measurement.Length.ratios[this.unit]) === 'undefined') {
27400 		throw "Unknown unit: " + options.unit;
27401 	}
27402 };
27403 
27404 ilib.Measurement.Length.ratios = {
27405 	/*              index, µm           mm           cm           inch         dm           foot          yard          m             dam            hm              km              mile            nm            Mm             Gm             */ 
27406 	"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           ],
27407 	"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           ],
27408 	"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            ],
27409     "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   ],
27410     "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            ],
27411     "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   ],
27412     "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  ],
27413 	"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            ],
27414 	"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            ],
27415 	"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            ],
27416 	"kilometer":    [ 11,  1e9,         1e6,         1e5,         39370.1,     1e4,         3280.84,      1093.61,      1000,         100,           10,             1,              0.621373,     0.539957,     0.001,          1e-4            ],
27417     "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      ],
27418     "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        ],
27419 	"megameter":    [ 14,  1e12,        1e9,         1e6,         3.93701e7,   1e5,         3.28084e6,    1.09361e6,    1e4,          1000,          100,            10,             621.373,      539.957,      1,              0.001           ],        
27420     "gigameter":    [ 15,  1e15,        1e12,        1e9,         3.93701e10,  1e8,         3.28084e9,    1.09361e9,    1e7,          1e6,           1e5,            1e4,            621373.0,     539957.0,     1000,           1               ]	
27421 };
27422 
27423 ilib.Measurement.Length.metricSystem = {
27424     "micrometer": 1,
27425     "millimeter": 2,
27426     "centimeter": 3,
27427     "decimeter": 5,
27428     "meter": 8,
27429     "decameter": 9,
27430     "hectometer": 10,
27431     "kilometer": 11,
27432     "megameter": 14,
27433     "gigameter": 15
27434 };
27435 ilib.Measurement.Length.imperialSystem = {
27436     "inch": 4,
27437     "foot": 6,
27438     "yard": 7,
27439     "mile": 12,
27440     "nauticalmile": 13
27441 };
27442 ilib.Measurement.Length.uscustomarySystem = {
27443     "inch": 4,
27444     "foot": 6,
27445     "yard": 7,
27446     "mile": 12,
27447     "nauticalmile": 13
27448 };
27449 
27450 ilib.Measurement.Length.metricToUScustomary = {
27451     "micrometer": "inch",
27452     "millimeter": "inch",
27453     "centimeter": "inch",
27454     "decimeter": "inch",
27455     "meter": "yard",
27456     "decameter": "yard",
27457     "hectometer": "mile",
27458     "kilometer": "mile",
27459     "megameter": "nauticalmile",
27460     "gigameter": "nauticalmile"
27461 };
27462 ilib.Measurement.Length.usCustomaryToMetric = {
27463     "inch": "centimeter",
27464     "foot": "centimeter",
27465     "yard": "meter",
27466     "mile": "kilometer",
27467     "nauticalmile": "kilometer"
27468 };
27469 
27470 ilib.Measurement.Length.prototype = new ilib.Measurement({});
27471 ilib.Measurement.Length.prototype.parent = ilib.Measurement;
27472 ilib.Measurement.Length.prototype.constructor = ilib.Measurement.Length;
27473 
27474 /**
27475  * Return the type of this measurement. Examples are "mass",
27476  * "length", "speed", etc. Measurements can only be converted
27477  * to measurements of the same type.<p>
27478  * 
27479  * The type of the units is determined automatically from the 
27480  * units. For example, the unit "grams" is type "mass". Use the 
27481  * static call {@link ilib.Measurement.getAvailableUnits}
27482  * to find out what units this version of ilib supports.
27483  *  
27484  * @return {string} the name of the type of this measurement
27485  */
27486 ilib.Measurement.Length.prototype.getMeasure = function() {
27487 	return "length";
27488 };
27489 
27490 /**
27491  * Localize the measurement to the commonly used measurement in that locale. For example
27492  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
27493  * the formatted number should be automatically converted to the most appropriate 
27494  * measure in the other system, in this case, mph. The formatted result should
27495  * appear as "37.3 mph". 
27496  * 
27497  * @abstract
27498  * @param {string} locale current locale string
27499  * @returns {ilib.Measurement} a new instance that is converted to locale
27500  */
27501 ilib.Measurement.Length.prototype.localize = function(locale) {
27502     var to;
27503     if (locale === "en-US" || locale === "en-GB") {
27504         to = ilib.Measurement.Length.metricToUScustomary[this.unit] || this.unit;
27505     } else {
27506         to = ilib.Measurement.Length.usCustomaryToMetric[this.unit] || this.unit;
27507     }
27508     return new ilib.Measurement.Length({
27509         unit: to,
27510         amount: this
27511     });
27512 };
27513 
27514 /**
27515  * Return a new measurement instance that is converted to a new
27516  * measurement unit. Measurements can only be converted
27517  * to measurements of the same type.<p>
27518  *  
27519  * @param {string} to The name of the units to convert to
27520  * @return {ilib.Measurement|undefined} the converted measurement
27521  * or undefined if the requested units are for a different
27522  * measurement type 
27523  */
27524 ilib.Measurement.Length.prototype.convert = function(to) {
27525 	if (!to || typeof(ilib.Measurement.Length.ratios[this.normalizeUnits(to)]) === 'undefined') {
27526 		return undefined;
27527 	}
27528 	return new ilib.Measurement({
27529 		unit: to,
27530 		amount: this
27531 	});
27532 };
27533 
27534 /**
27535  * Scale the measurement unit to an acceptable level. The scaling
27536  * happens so that the integer part of the amount is as small as
27537  * possible without being below zero. This will result in the 
27538  * largest units that can represent this measurement without
27539  * fractions. Measurements can only be scaled to other measurements 
27540  * of the same type.
27541  * 
27542  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
27543  * or undefined if the system can be inferred from the current measure
27544  * @return {ilib.Measurement} a new instance that is scaled to the 
27545  * right level
27546  */
27547 ilib.Measurement.Length.prototype.scale = function(measurementsystem) {
27548     var mSystem;    
27549     if (measurementsystem === "metric" || (typeof(measurementsystem) === 'undefined' 
27550             && typeof(ilib.Measurement.Length.metricSystem[this.unit]) !== 'undefined')) {
27551         mSystem = ilib.Measurement.Length.metricSystem;
27552     } else if (measurementsystem === "imperial" || (typeof(measurementsystem) === 'undefined' 
27553             && typeof(ilib.Measurement.Length.imperialSystem[this.unit]) !== 'undefined')) {
27554         mSystem = ilib.Measurement.Length.imperialSystem;
27555     } else if (measurementsystem === "uscustomary" || (typeof(measurementsystem) === 'undefined' 
27556             && typeof(ilib.Measurement.Length.uscustomarySystem[this.unit]) !== 'undefined')) {
27557         mSystem = ilib.Measurement.Length.uscustomarySystem;
27558     } else {
27559         return new ilib.Measurement.Length({
27560 			unit: this.unit,
27561 			amount: this.amount
27562 		});
27563     }    
27564     
27565     var length = this.amount;
27566     var munit = this.unit;
27567     var fromRow = ilib.Measurement.Length.ratios[this.unit];
27568     
27569     for (var m in mSystem) {
27570         var tmp = this.amount * fromRow[mSystem[m]];
27571         if (tmp < 1) break;
27572         length = tmp;
27573         munit = m;
27574     }
27575     
27576     return new ilib.Measurement.Length({
27577 		unit: munit,
27578 		amount: length
27579     });
27580 };
27581 
27582 ilib.Measurement.Length.aliases = {
27583 	"miles": "mile",
27584 	"mile":"mile",
27585 	"nauticalmiles": "nauticalmile",
27586 	"nautical mile": "nauticalmile",
27587 	"nautical miles": "nauticalmile",
27588 	"nauticalmile":"nauticalmile",
27589 	"yards": "yard",
27590 	"yard": "yard",
27591 	"feet": "foot",
27592 	"foot": "foot",
27593 	"inches": "inch",
27594 	"inch": "inch",
27595 	"meters": "meter",
27596 	"metre": "meter",
27597 	"metres": "meter",
27598 	"m": "meter",
27599 	"meter": "meter",        
27600 	"micrometers": "micrometer",
27601 	"micrometres": "micrometer",
27602 	"micrometre": "micrometer",
27603 	"µm": "micrometer",
27604 	"micrometer": "micrometer",
27605 	"millimeters": "millimeter",
27606 	"millimetres": "millimeter",
27607 	"millimetre": "millimeter",
27608 	"mm": "millimeter",
27609 	"millimeter": "millimeter",
27610 	"centimeters": "centimeter",
27611 	"centimetres": "centimeter",
27612 	"centimetre": "centimeter",
27613 	"cm": "centimeter",
27614 	"centimeter": "centimeter",
27615 	"decimeters": "decimeter",
27616 	"decimetres": "decimeter",
27617 	"decimetre": "decimeter",
27618 	"dm": "decimeter",
27619 	"decimeter": "decimeter",
27620 	"decameters": "decameter",
27621 	"decametres": "decameter",
27622 	"decametre": "decameter",
27623 	"dam": "decameter",
27624 	"decameter": "decameter",
27625 	"hectometers": "hectometer",
27626 	"hectometres": "hectometer",
27627 	"hectometre": "hectometer",
27628 	"hm": "hectometer",
27629 	"hectometer": "hectometer",
27630 	"kilometers": "kilometer",
27631 	"kilometres": "kilometer",
27632 	"kilometre": "kilometer",
27633 	"km": "kilometer",
27634 	"kilometer": "kilometer",
27635 	"megameters": "megameter",
27636 	"megametres": "megameter",
27637 	"megametre": "megameter",
27638 	"Mm": "megameter",
27639 	"megameter": "megameter",
27640 	"gigameters": "gigameter",
27641 	"gigametres": "gigameter",
27642 	"gigametre": "gigameter",
27643 	"Gm": "gigameter",
27644 	"gigameter": "gigameter"
27645 };
27646 
27647 /**
27648  * Convert a length to another measure.
27649  * @static
27650  * @param to {string} unit to convert to
27651  * @param from {string} unit to convert from
27652  * @param length {number} amount to be convert
27653  * @returns {number|undefined} the converted amount
27654  */
27655 ilib.Measurement.Length.convert = function(to, from, length) {
27656     from = ilib.Measurement.Length.aliases[from] || from;
27657     to = ilib.Measurement.Length.aliases[to] || to;
27658 	var fromRow = ilib.Measurement.Length.ratios[from];
27659 	var toRow = ilib.Measurement.Length.ratios[to];
27660 	if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
27661 		return undefined;
27662 	}
27663 	return length * fromRow[toRow[0]];
27664 };
27665 
27666 /**
27667  * @private
27668  * @static
27669  */
27670 ilib.Measurement.Length.getMeasures = function () {
27671 	var ret = [];
27672 	for (var m in ilib.Measurement.Length.ratios) {
27673 		ret.push(m);
27674 	}
27675 	return ret;
27676 };
27677 
27678 //register with the factory method
27679 ilib.Measurement._constructors["length"] = ilib.Measurement.Length;
27680 
27681 /*
27682  * Speed.js - Unit conversions for Speeds/speeds
27683  * 
27684  * Copyright © 2014, JEDLSoft
27685  *
27686  * Licensed under the Apache License, Version 2.0 (the "License");
27687  * you may not use this file except in compliance with the License.
27688  * You may obtain a copy of the License at
27689  *
27690  *     http://www.apache.org/licenses/LICENSE-2.0
27691  *
27692  * Unless required by applicable law or agreed to in writing, software
27693  * distributed under the License is distributed on an "AS IS" BASIS,
27694  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27695  *
27696  * See the License for the specific language governing permissions and
27697  * limitations under the License.
27698  */
27699 
27700 /*
27701 !depends 
27702 ilibglobal.js
27703 unit.js
27704 */
27705 
27706 /**
27707  * @class
27708  * Create a new speed measurement instance.
27709  * 
27710  * @constructor
27711  * @extends ilib.Measurement
27712  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
27713  * the construction of this instance
27714  */
27715 ilib.Measurement.Speed = function (options) {
27716 	this.unit = "meters/second";
27717 	this.amount = 0;
27718 	this.aliases = ilib.Measurement.Speed.aliases; // share this table in all instances
27719 	
27720 	if (options) {
27721 		if (typeof(options.unit) !== 'undefined') {
27722 			this.originalUnit = options.unit;
27723 			this.unit = this.aliases[options.unit] || options.unit;
27724 		}
27725 		
27726 		if (typeof(options.amount) === 'object') {
27727 			if (options.amount.getMeasure() === "speed") {
27728 				this.amount = ilib.Measurement.Speed.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
27729 			} else {
27730 				throw "Cannot convert units " + options.amount.unit + " to a speed";
27731 			}
27732 		} else if (typeof(options.amount) !== 'undefined') {
27733 			this.amount = parseFloat(options.amount);
27734 		}
27735 	}
27736 	
27737 	if (typeof(ilib.Measurement.Speed.ratios[this.unit]) === 'undefined') {
27738 		throw "Unknown unit: " + options.unit;
27739 	}
27740 };
27741 
27742 ilib.Measurement.Speed.ratios = {
27743 	/*                 index, k/h         f/s         miles/h      knot         m/s        km/s         miles/s */
27744     "kilometer/hour":   [ 1,  1,          0.911344,   0.621371,    0.539957,    0.277778,  2.77778e-4,  1.72603109e-4 ],
27745 	"feet/second":      [ 2,  1.09728,    1,          0.681818,    0.592484,    0.3048,    3.048e-4,    1.89393939e-4 ],  
27746     "miles/hour":       [ 3,  1.60934,    1.46667,    1,           0.868976,    0.44704,   4.4704e-4,   2.77777778e-4 ],
27747     "knot":             [ 4,  1.852,      1.68781,    1.15078,     1,           0.514444,  5.14444e-4,  3.19660958e-4 ],
27748   	"meters/second":    [ 5,  3.6,        3.28084,    2.236936,    1.94384,     1,         0.001,       6.21371192e-4 ],	
27749     "kilometer/second": [ 6,  3600,       3280.8399,  2236.93629,  1943.84449,  1000,      1,           0.621371192   ],
27750     "miles/second":     [ 7,  5793.6384,  5280,       3600,        3128.31447,  1609.344,  1.609344,    1             ]
27751 };
27752 
27753 ilib.Measurement.Speed.metricSystem = {
27754     "kilometer/hour": 1,
27755     "meters/second": 5,
27756     "kilometer/second": 6
27757 };
27758 ilib.Measurement.Speed.imperialSystem = {
27759     "feet/second": 2,
27760     "miles/hour": 3,
27761     "knot": 4,
27762     "miles/second": 7
27763 };
27764 ilib.Measurement.Speed.uscustomarySystem = {
27765     "feet/second": 2,
27766     "miles/hour": 3,
27767     "knot": 4,
27768     "miles/second": 7
27769 };
27770 
27771 ilib.Measurement.Speed.metricToUScustomary = {
27772     "kilometer/hour": "miles/hour",
27773     "meters/second": "feet/second",
27774     "kilometer/second": "miles/second"
27775 };
27776 ilib.Measurement.Speed.UScustomaryTometric = {
27777     "miles/hour": "kilometer/hour",
27778     "feet/second": "meters/second",
27779     "miles/second": "kilometer/second",
27780     "knot": "kilometer/hour"
27781 };
27782 
27783 ilib.Measurement.Speed.prototype = new ilib.Measurement({});
27784 ilib.Measurement.Speed.prototype.parent = ilib.Measurement;
27785 ilib.Measurement.Speed.prototype.constructor = ilib.Measurement.Speed;
27786 
27787 /**
27788  * Return the type of this measurement. Examples are "mass",
27789  * "length", "speed", etc. Measurements can only be converted
27790  * to measurements of the same type.<p>
27791  * 
27792  * The type of the units is determined automatically from the 
27793  * units. For example, the unit "grams" is type "mass". Use the 
27794  * static call {@link ilib.Measurement.getAvailableUnits}
27795  * to find out what units this version of ilib supports.
27796  *  
27797  * @return {string} the name of the type of this measurement
27798  */
27799 ilib.Measurement.Speed.prototype.getMeasure = function() {
27800 	return "speed";
27801 };
27802 
27803 /**
27804  * Return a new measurement instance that is converted to a new
27805  * measurement unit. Measurements can only be converted
27806  * to measurements of the same type.<p>
27807  *  
27808  * @param {string} to The name of the units to convert to
27809  * @return {ilib.Measurement|undefined} the converted measurement
27810  * or undefined if the requested units are for a different
27811  * measurement type 
27812  */
27813 ilib.Measurement.Speed.prototype.convert = function(to) {
27814 	if (!to || typeof(ilib.Measurement.Speed.ratios[this.normalizeUnits(to)]) === 'undefined') {
27815 		return undefined;
27816 	}
27817 	return new ilib.Measurement({
27818 		unit: to,
27819 		amount: this
27820 	});
27821 };
27822 
27823 /**
27824  * Scale the measurement unit to an acceptable level. The scaling
27825  * happens so that the integer part of the amount is as small as
27826  * possible without being below zero. This will result in the 
27827  * largest units that can represent this measurement without
27828  * fractions. Measurements can only be scaled to other measurements 
27829  * of the same type.
27830  * 
27831  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
27832  * or undefined if the system can be inferred from the current measure
27833  * @return {ilib.Measurement} a new instance that is scaled to the 
27834  * right level
27835  */
27836 ilib.Measurement.Speed.prototype.scale = function(measurementsystem) {
27837 	var mSystem;
27838 	if (measurementsystem === "metric" ||
27839 	    (typeof (measurementsystem) === 'undefined' && typeof (ilib.Measurement.Speed.metricSystem[this.unit]) !== 'undefined')) {
27840 		mSystem = ilib.Measurement.Speed.metricSystem;
27841 	} else if (measurementsystem === "imperial" ||
27842 	    (typeof (measurementsystem) === 'undefined' && typeof (ilib.Measurement.Speed.imperialSystem[this.unit]) !== 'undefined')) {
27843 		mSystem = ilib.Measurement.Speed.imperialSystem;
27844 	} else if (measurementsystem === "uscustomary" ||
27845 	    (typeof (measurementsystem) === 'undefined' && typeof (ilib.Measurement.Speed.uscustomarySystem[this.unit]) !== 'undefined')) {
27846 		mSystem = ilib.Measurement.Speed.uscustomarySystem;
27847 	} else {
27848 		return new ilib.Measurement.Speed({
27849 		    unit: this.unit,
27850 		    amount: this.amount
27851 		});
27852 	}
27853 
27854 	var speed = this.amount;
27855 	var munit = this.unit;
27856 	var fromRow = ilib.Measurement.Speed.ratios[this.unit];
27857 
27858 	for ( var m in mSystem) {
27859 		var tmp = this.amount * fromRow[mSystem[m]];
27860 		if (tmp < 1)
27861 			break;
27862 		speed = tmp;
27863 		munit = m;
27864 	}
27865 
27866 	return new ilib.Measurement.Speed({
27867 	    unit: munit,
27868 	    amount: speed
27869 	});
27870 };
27871 
27872 /**
27873  * Localize the measurement to the commonly used measurement in that locale. For example
27874  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
27875  * the formatted number should be automatically converted to the most appropriate 
27876  * measure in the other system, in this case, mph. The formatted result should
27877  * appear as "37.3 mph". 
27878  * 
27879  * @abstract
27880  * @param {string} locale current locale string
27881  * @returns {ilib.Measurement} a new instance that is converted to locale
27882  */
27883 ilib.Measurement.Speed.prototype.localize = function(locale) {
27884     var to;
27885     if (locale === "en-US" || locale === "en-GB") {
27886         to = ilib.Measurement.Speed.metricToUScustomary[this.unit] || this.unit;
27887     } else {
27888         to = ilib.Measurement.Speed.UScustomaryTometric[this.unit] || this.unit;
27889     }
27890     return new ilib.Measurement.Speed({
27891 		unit: to,
27892 		amount: this
27893     });
27894 };
27895 
27896 ilib.Measurement.Speed.aliases = {
27897     "foot/sec": "feet/second",
27898     "foot/s": "feet/second",
27899     "feet/s": "feet/second",
27900     "f/s": "feet/second",
27901     "feet/second": "feet/second",
27902     "feet/sec": "feet/second",
27903     "meter/sec": "meters/second",
27904     "meter/s": "meters/second",
27905     "meters/s": "meters/second",
27906     "metre/sec": "meters/second",
27907     "metre/s": "meters/second",
27908     "metres/s": "meters/second",
27909     "mt/sec": "meters/second",
27910     "m/sec": "meters/second",
27911     "mt/s": "meters/second",
27912     "m/s": "meters/second",
27913     "mps": "meters/second",
27914     "meters/second": "meters/second",
27915     "meters/sec": "meters/second",
27916     "kilometer/hour": "kilometer/hour",
27917     "km/hour": "kilometer/hour",
27918     "kilometers/hour": "kilometer/hour",
27919     "kmh": "kilometer/hour",
27920     "km/h": "kilometer/hour",
27921     "kilometer/h": "kilometer/hour",
27922     "kilometers/h": "kilometer/hour",
27923     "km/hr": "kilometer/hour",
27924     "kilometer/hr": "kilometer/hour",
27925     "kilometers/hr": "kilometer/hour",
27926     "kilometre/hour": "kilometer/hour",
27927     "mph": "miles/hour",
27928     "mile/hour": "miles/hour",
27929     "mile/hr": "miles/hour",
27930     "mile/h": "miles/hour",
27931     "miles/h": "miles/hour",
27932     "miles/hr": "miles/hour",
27933     "miles/hour": "miles/hour",
27934     "kn": "knot",
27935     "kt": "knot",
27936     "kts": "knot",
27937     "knots": "knot",
27938     "nm/h": "knot",
27939     "nm/hr": "knot",
27940     "nauticalmile/h": "knot",
27941     "nauticalmile/hr": "knot",
27942     "nauticalmile/hour": "knot",
27943     "nauticalmiles/hr": "knot",
27944     "nauticalmiles/hour": "knot",
27945     "knot": "knot",
27946     "kilometer/second": "kilometer/second",
27947     "kilometer/sec": "kilometer/second",
27948     "kilometre/sec": "kilometer/second",
27949     "Kilometre/sec": "kilometer/second",
27950     "kilometers/second": "kilometer/second",
27951     "kilometers/sec": "kilometer/second",
27952     "kilometres/sec": "kilometer/second",
27953     "Kilometres/sec": "kilometer/second",
27954     "km/sec": "kilometer/second",
27955     "Km/s": "kilometer/second",
27956     "km/s": "kilometer/second",
27957     "miles/second": "miles/second",
27958     "miles/sec": "miles/second",
27959     "miles/s": "miles/second",
27960     "mile/s": "miles/second",
27961     "mile/sec": "miles/second",
27962     "Mile/s": "miles/second"
27963 };
27964 
27965 /**
27966  * Convert a speed to another measure.
27967  * @static
27968  * @param to {string} unit to convert to
27969  * @param from {string} unit to convert from
27970  * @param speed {number} amount to be convert
27971  * @returns {number|undefined} the converted amount
27972  */
27973 ilib.Measurement.Speed.convert = function(to, from, speed) {
27974     from = ilib.Measurement.Speed.aliases[from] || from;
27975     to = ilib.Measurement.Speed.aliases[to] || to;
27976 	var fromRow = ilib.Measurement.Speed.ratios[from];
27977 	var toRow = ilib.Measurement.Speed.ratios[to];
27978 	if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
27979 		return undefined;
27980 	}	
27981 	var result = speed * fromRow[toRow[0]];
27982     return result;
27983 };
27984 
27985 /**
27986  * @private
27987  * @static
27988  */
27989 ilib.Measurement.Speed.getMeasures = function () {
27990 	var ret = [];
27991 	for (var m in ilib.Measurement.Speed.ratios) {
27992 		ret.push(m);
27993 	}
27994 	return ret;
27995 };
27996 
27997 //register with the factory method
27998 ilib.Measurement._constructors["speed"] = ilib.Measurement.Speed;
27999 
28000 /*
28001  * digitalStorage.js - Unit conversions for Digital Storage
28002  * 
28003  * Copyright © 2014, JEDLSoft
28004  *
28005  * Licensed under the Apache License, Version 2.0 (the "License");
28006  * you may not use this file except in compliance with the License.
28007  * You may obtain a copy of the License at
28008  *
28009  *     http://www.apache.org/licenses/LICENSE-2.0
28010  *
28011  * Unless required by applicable law or agreed to in writing, software
28012  * distributed under the License is distributed on an "AS IS" BASIS,
28013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28014  *
28015  * See the License for the specific language governing permissions and
28016  * limitations under the License.
28017  */
28018 
28019 /*
28020 !depends 
28021 ilibglobal.js 
28022 unit.js
28023 */
28024 
28025 /**
28026  * @class
28027  * Create a new DigitalStorage measurement instance.
28028  *  
28029  * @constructor
28030  * @extends ilib.Measurement
28031  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
28032  * the construction of this instance
28033  */
28034 ilib.Measurement.DigitalStorage = function (options) {
28035 	this.unit = "bit";
28036 	this.amount = 0;
28037 	this.aliases = ilib.Measurement.DigitalStorage.aliases; // share this table in all instances
28038 	
28039 	if (options) {
28040 		if (typeof(options.unit) !== 'undefined') {
28041 			this.originalUnit = options.unit;
28042 			this.unit = this.aliases[options.unit] || options.unit;
28043 		}
28044 		
28045 		if (typeof(options.amount) === 'object') {
28046 			if (options.amount.getMeasure() === "digitalStorage") {
28047 				this.amount = ilib.Measurement.DigitalStorage.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
28048 			} else {
28049 				throw "Cannot convert unit " + options.amount.unit + " to a digitalStorage";
28050 			}
28051 		} else if (typeof(options.amount) !== 'undefined') {
28052 			this.amount = parseFloat(options.amount);
28053 		}
28054 	}
28055 	
28056 	if (typeof(ilib.Measurement.DigitalStorage.ratios[this.unit]) === 'undefined') {
28057 		throw "Unknown unit: " + options.unit;
28058 	}
28059 };
28060 
28061 ilib.Measurement.DigitalStorage.ratios = {
28062     /*                 bit             byte            kb              kB              mb              mB              gb               gB               tb               tB               pb               pB   */           
28063 	"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 ],
28064     "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 ],
28065     "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 ],
28066     "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 ],
28067     "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 ],
28068     "megabyte": [ 6,   8388608,        1048576,        8192,           1024,           8,              1,              0.0078125,       0.0009765625,    7.629394531e-6,  9.536743164e-7,  7.450580597e-9,  9.313225746e-10 ],
28069     "gigabit":  [ 7,   1073741824,     134217728,      1048576,        131072,         1024,           128,            1,               0.125,           0.0009765625,    1.220703125e-4,  9.536743164e-7,  1.192092896e-7  ],
28070     "gigabyte": [ 8,   8589934592,     1073741824,     8388608,        1048576,        8192,           1024,           8,               1,               0.0078125,       0.0009765625,    7.629394531e-6,  9.536743164e-7  ],
28071     "terabit":  [ 9,   1.099511628e12, 137438953472,   1073741824,     134217728,      1048576,        131072,         1024,            128,             1,               0.125,           0.0009765625,    1.220703125e-4  ],
28072     "terabyte": [ 10,  8.796093022e12, 1.099511628e12, 8589934592,     1073741824,     8388608,        1048576,        8192,            1024,            8,               1,               0.0078125,       0.0009765625    ],
28073     "petabit":  [ 11,  1.125899907e15, 1.407374884e14, 1.099511628e12, 137438953472,   1073741824,     134217728,      1048576,         131072,          1024,            128,             1,               0.125           ],
28074     "petabyte": [ 12,  9.007199255e15, 1.125899907e15, 8.796093022e12, 1.099511628e12, 8589934592,     1073741824,     8388608,         1048576,         8192,            1024,            8,               1               ]
28075 };
28076 ilib.Measurement.DigitalStorage.prototype = new ilib.Measurement({});
28077 ilib.Measurement.DigitalStorage.prototype.parent = ilib.Measurement;
28078 ilib.Measurement.DigitalStorage.prototype.constructor = ilib.Measurement.DigitalStorage;
28079 
28080 /**
28081  * Return the type of this measurement. Examples are "mass",
28082  * "length", "speed", etc. Measurements can only be converted
28083  * to measurements of the same type.<p>
28084  * 
28085  * The type of the units is determined automatically from the 
28086  * units. For example, the unit "grams" is type "mass". Use the 
28087  * static call {@link ilib.Measurement.getAvailableUnits}
28088  * to find out what units this version of ilib supports.
28089  *  
28090  * @return {string} the name of the type of this measurement
28091  */
28092 ilib.Measurement.DigitalStorage.prototype.getMeasure = function() {
28093 	return "digitalStorage";
28094 };
28095 
28096 /**
28097  * Return a new measurement instance that is converted to a new
28098  * measurement unit. Measurements can only be converted
28099  * to measurements of the same type.<p>
28100  *  
28101  * @param {string} to The name of the units to convert to
28102  * @return {ilib.Measurement|undefined} the converted measurement
28103  * or undefined if the requested units are for a different
28104  * measurement type
28105  * 
28106  */
28107 ilib.Measurement.DigitalStorage.prototype.convert = function(to) {
28108 	if (!to || typeof(ilib.Measurement.DigitalStorage.ratios[this.normalizeUnits(to)]) === 'undefined') {
28109 		return undefined;
28110 	}
28111 	return new ilib.Measurement({
28112 		unit: to,
28113 		amount: this
28114 	});
28115 };
28116 
28117 /**
28118  * Localize the measurement to the commonly used measurement in that locale. For example
28119  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
28120  * the formatted number should be automatically converted to the most appropriate 
28121  * measure in the other system, in this case, mph. The formatted result should
28122  * appear as "37.3 mph". 
28123  * 
28124  * @abstract
28125  * @param {string} locale current locale string
28126  * @returns {ilib.Measurement} a new instance that is converted to locale
28127  */
28128 ilib.Measurement.DigitalStorage.prototype.localize = function(locale) {
28129     return new ilib.Measurement.DigitalStorage({
28130         unit: this.unit,
28131         amount: this.amount
28132     });
28133 };
28134 
28135 /**
28136  * Scale the measurement unit to an acceptable level. The scaling
28137  * happens so that the integer part of the amount is as small as
28138  * possible without being below zero. This will result in the 
28139  * largest units that can represent this measurement without
28140  * fractions. Measurements can only be scaled to other measurements 
28141  * of the same type.
28142  * 
28143  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
28144  * or undefined if the system can be inferred from the current measure
28145  * @return {ilib.Measurement} a new instance that is scaled to the 
28146  * right level
28147  */
28148 ilib.Measurement.DigitalStorage.prototype.scale = function(measurementsystem) {
28149     
28150     var fromRow = ilib.Measurement.DigitalStorage.ratios[this.unit];    
28151     var dStorage = this.amount;
28152     var munit = this.unit;
28153     var i=1;
28154     
28155     for (var m in ilib.Measurement.DigitalStorage.ratios) {
28156         var tmp = this.amount * fromRow[i];
28157         if (tmp < 1) break;
28158         dStorage = tmp;
28159         munit = m;
28160         ++i
28161     }
28162     
28163     return new ilib.Measurement.DigitalStorage({
28164 	unit: munit,
28165 	amount: dStorage
28166     });    
28167 };
28168 
28169 ilib.Measurement.DigitalStorage.aliases = {
28170     "bits": "bit",
28171     "bit": "bit",
28172     "Bits": "bit",
28173     "Bit": "bit",
28174     "byte": "byte",
28175     "bytes": "byte",
28176     "Byte": "byte",
28177     "Bytes": "byte",
28178     "kilobits": "kilobit",
28179     "Kilobits": "kilobit",
28180     "KiloBits": "kilobit",
28181     "kiloBits": "kilobit",
28182     "kilobit": "kilobit",
28183     "Kilobit": "kilobit",
28184     "kiloBit": "kilobit",
28185     "KiloBit": "kilobit",
28186     "kb": "kilobit",
28187     "Kb": "kilobit",
28188     "kilobyte": "kilobyte",
28189     "Kilobyte": "kilobyte",
28190     "kiloByte": "kilobyte",
28191     "KiloByte": "kilobyte",
28192     "kilobytes": "kilobyte",
28193     "Kilobytes": "kilobyte",
28194     "kiloBytes": "kilobyte",
28195     "KiloBytes": "kilobyte",
28196     "kB": "kilobyte",
28197     "KB": "kilobyte",
28198     "megabit": "megabit",
28199     "Megabit": "megabit",
28200     "megaBit": "megabit",
28201     "MegaBit": "megabit",
28202     "megabits": "megabit",
28203     "Megabits": "megabit",
28204     "megaBits": "megabit",
28205     "MegaBits": "megabit",
28206     "Mb": "megabit",
28207     "mb": "megabit",
28208     "megabyte": "megabyte",
28209     "Megabyte": "megabyte",
28210     "megaByte": "megabyte",
28211     "MegaByte": "megabyte",
28212     "megabytes": "megabyte",
28213     "Megabytes": "megabyte",
28214     "megaBytes": "megabyte",
28215     "MegaBytes": "megabyte",
28216     "MB": "megabyte",
28217     "mB": "megabyte",
28218     "gigabit": "gigabit",
28219     "Gigabit": "gigabit",
28220     "gigaBit": "gigabit",
28221     "GigaBit": "gigabit",
28222     "gigabits": "gigabit",
28223     "Gigabits": "gigabit",
28224     "gigaBits": "gigabyte",
28225     "GigaBits": "gigabit",
28226     "Gb": "gigabit",
28227     "gb": "gigabit",
28228     "gigabyte": "gigabyte",
28229     "Gigabyte": "gigabyte",
28230     "gigaByte": "gigabyte",
28231     "GigaByte": "gigabyte",
28232     "gigabytes": "gigabyte",
28233     "Gigabytes": "gigabyte",
28234     "gigaBytes": "gigabyte",
28235     "GigaBytes": "gigabyte",
28236     "GB": "gigabyte",
28237     "gB": "gigabyte",
28238     "terabit": "terabit",
28239     "Terabit": "terabit",
28240     "teraBit": "terabit",
28241     "TeraBit": "terabit",
28242     "terabits": "terabit",
28243     "Terabits": "terabit",
28244     "teraBits": "terabit",
28245     "TeraBits": "terabit",
28246     "tb": "terabit",
28247     "Tb": "terabit",
28248     "terabyte": "terabyte",
28249     "Terabyte": "terabyte",
28250     "teraByte": "terabyte",
28251     "TeraByte": "terabyte",
28252     "terabytes": "terabyte",
28253     "Terabytes": "terabyte",
28254     "teraBytes": "terabyte",
28255     "TeraBytes": "terabyte",
28256     "TB": "terabyte",
28257     "tB": "terabyte",
28258     "petabit": "petabit",
28259     "Petabit": "petabit",
28260     "petaBit": "petabit",
28261     "PetaBit": "petabit",
28262     "petabits": "petabit",
28263     "Petabits": "petabit",
28264     "petaBits": "petabit",
28265     "PetaBits": "petabit",
28266     "pb": "petabit",
28267     "Pb": "petabit",
28268     "petabyte": "petabyte",
28269     "Petabyte": "petabyte",
28270     "petaByte": "petabyte",
28271     "PetaByte": "petabyte",
28272     "petabytes": "petabyte",
28273     "Petabytes": "petabyte",
28274     "petaBytes": "petabyte",
28275     "PetaBytes": "petabyte",
28276     "PB": "petabyte",
28277     "pB": "petabyte"
28278 };
28279 
28280 /**
28281  * Convert a digitalStorage to another measure.
28282  * @static
28283  * @param to {string} unit to convert to
28284  * @param from {string} unit to convert from
28285  * @param digitalStorage {number} amount to be convert
28286  * @returns {number|undefined} the converted amount
28287  */
28288 ilib.Measurement.DigitalStorage.convert = function(to, from, digitalStorage) {
28289     from = ilib.Measurement.DigitalStorage.aliases[from] || from;
28290     to = ilib.Measurement.DigitalStorage.aliases[to] || to;
28291 	var fromRow = ilib.Measurement.DigitalStorage.ratios[from];
28292 	var toRow = ilib.Measurement.DigitalStorage.ratios[to];
28293 	if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
28294 		return undefined;
28295 	}	
28296 	var result = digitalStorage * fromRow[toRow[0]];
28297     return result;
28298 };
28299 
28300 /**
28301  * @private
28302  * @static
28303  */
28304 ilib.Measurement.DigitalStorage.getMeasures = function () {
28305 	var ret = [];
28306 	for (var m in ilib.Measurement.DigitalStorage.ratios) {
28307 		ret.push(m);
28308 	}
28309 	return ret;
28310 };
28311 
28312 //register with the factory method
28313 ilib.Measurement._constructors["digitalStorage"] = ilib.Measurement.DigitalStorage;
28314 
28315 /*
28316  * temperature.js - Unit conversions for Temperature/temperature
28317  * 
28318  * Copyright © 2014, JEDLSoft
28319  *
28320  * Licensed under the Apache License, Version 2.0 (the "License");
28321  * you may not use this file except in compliance with the License.
28322  * You may obtain a copy of the License at
28323  *
28324  *     http://www.apache.org/licenses/LICENSE-2.0
28325  *
28326  * Unless required by applicable law or agreed to in writing, software
28327  * distributed under the License is distributed on an "AS IS" BASIS,
28328  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28329  *
28330  * See the License for the specific language governing permissions and
28331  * limitations under the License.
28332  */
28333 
28334 /*
28335 !depends 
28336 ilibglobal.js
28337 unit.js
28338 */
28339 
28340 /**
28341  * @class
28342  * Create a new Temperature measurement instance.
28343  *  
28344  * @constructor
28345  * @extends ilib.Measurement
28346  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
28347  * the construction of this instance
28348  */
28349 ilib.Measurement.Temperature = function (options) {
28350 	this.unit = "celsius";
28351 	this.amount = 0;
28352 	this.aliases = ilib.Measurement.Temperature.aliases; // share this table in all instances
28353 
28354 	if (options) {
28355 		if (typeof(options.unit) !== 'undefined') {
28356 			this.originalUnit = options.unit;
28357 			this.unit = this.aliases[options.unit] || options.unit;
28358 		}
28359 
28360 		if (typeof(options.amount) === 'object') {
28361 			if (options.amount.getMeasure() === "temperature") {
28362 				this.amount = ilib.Measurement.Temperature.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
28363 			} else {
28364 				throw "Cannot convert unit " + options.amount.unit + " to a temperature";
28365 			}
28366 		} else if (typeof(options.amount) !== 'undefined') {
28367 			this.amount = parseFloat(options.amount);
28368 		}
28369 	}
28370 };
28371 
28372 ilib.Measurement.Temperature.prototype = new ilib.Measurement({});
28373 ilib.Measurement.Temperature.prototype.parent = ilib.Measurement;
28374 ilib.Measurement.Temperature.prototype.constructor = ilib.Measurement.Temperature;
28375 
28376 /**
28377  * Return the type of this measurement. Examples are "mass",
28378  * "length", "speed", etc. Measurements can only be converted
28379  * to measurements of the same type.<p>
28380  * 
28381  * The type of the units is determined automatically from the 
28382  * units. For example, the unit "grams" is type "mass". Use the 
28383  * static call {@link ilib.Measurement.getAvailableUnits}
28384  * to find out what units this version of ilib supports.
28385  *  
28386  * @return {string} the name of the type of this measurement
28387  */
28388 ilib.Measurement.Temperature.prototype.getMeasure = function() {
28389 	return "temperature";
28390 };
28391 
28392 ilib.Measurement.Temperature.aliases = {
28393     "Celsius": "celsius",
28394     "celsius": "celsius",
28395     "C": "celsius",
28396     "centegrade": "celsius",
28397     "Centegrade": "celsius",
28398     "centigrade": "celsius",
28399     "Centigrade": "celsius",
28400     "fahrenheit": "fahrenheit",
28401     "Fahrenheit": "fahrenheit",
28402     "F": "fahrenheit",
28403     "kelvin": "kelvin",
28404     "K": "kelvin",
28405     "Kelvin": "kelvin",
28406     "°F": "fahrenheit",
28407     "℉": "fahrenheit",
28408     "℃": "celsius",
28409     "°C": "celsius"
28410 };
28411 
28412 /**
28413  * Return a new measurement instance that is converted to a new
28414  * measurement unit. Measurements can only be converted
28415  * to measurements of the same type.<p>
28416  *  
28417  * @param {string} to The name of the units to convert to
28418  * @return {ilib.Measurement|undefined} the converted measurement
28419  * or undefined if the requested units are for a different
28420  * measurement type 
28421  */
28422 ilib.Measurement.Temperature.prototype.convert = function(to) {
28423 	if (!to || typeof(ilib.Measurement.Temperature.ratios[this.normalizeUnits(to)]) === 'undefined') {
28424 		return undefined;
28425 	}
28426 	return new ilib.Measurement({
28427 		unit: to,
28428 		amount: this
28429 	});
28430 };
28431 
28432 /**
28433  * Convert a temperature to another measure.
28434  * @static
28435  * @param to {string} unit to convert to
28436  * @param from {string} unit to convert from
28437  * @param temperature {number} amount to be convert
28438  * @returns {number|undefined} the converted amount
28439  */
28440 ilib.Measurement.Temperature.convert = function(to, from, temperature) {
28441 	var result = 0;
28442 	from = ilib.Measurement.Temperature.aliases[from] || from;
28443 	to = ilib.Measurement.Temperature.aliases[to] || to;
28444 	if (from === to)
28445 		return temperature;
28446 
28447 	else if (from === "celsius") {
28448 		if (to === "fahrenheit") {
28449 			result = ((temperature * 9 / 5) + 32);
28450 		} else if (to === "kelvin") {
28451 			result = (temperature + 273.15);
28452 		}
28453 
28454 	} else if (from === "fahrenheit") {
28455 		if (to === "celsius") {
28456 			result = ((5 / 9 * (temperature - 32)));
28457 		} else if (to === "kelvin") {
28458 			result = ((temperature + 459.67) * 5 / 9);
28459 		}
28460 	} else if (from === "kelvin") {
28461 		if (to === "celsius") {
28462 			result = (temperature - 273.15);
28463 		} else if (to === "fahrenheit") {
28464 			result = ((temperature * 9 / 5) - 459.67);
28465 		}
28466 	}
28467 
28468 	return result;
28469 };
28470 
28471 /**
28472  * Scale the measurement unit to an acceptable level. The scaling
28473  * happens so that the integer part of the amount is as small as
28474  * possible without being below zero. This will result in the 
28475  * largest units that can represent this measurement without
28476  * fractions. Measurements can only be scaled to other measurements 
28477  * of the same type.
28478  * 
28479  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
28480  * or undefined if the system can be inferred from the current measure
28481  * @return {ilib.Measurement} a new instance that is scaled to the 
28482  * right level
28483  */
28484 ilib.Measurement.Temperature.prototype.scale = function(measurementsystem) {
28485     return new ilib.Measurement.Temperature({
28486         unit: this.unit,
28487         amount: this.amount
28488     }); 
28489 };
28490 
28491 /**
28492  * @private
28493  * @static
28494  */
28495 ilib.Measurement.Temperature.getMeasures = function () {
28496 	return ["celsius", "kelvin", "fahrenheit"];
28497 };
28498 ilib.Measurement.Temperature.metricToUScustomary = {
28499 	"celsius": "fahrenheit"
28500 };
28501 ilib.Measurement.Temperature.usCustomaryToMetric = {
28502 	"fahrenheit": "celsius"
28503 };
28504 
28505 /**
28506  * Localize the measurement to the commonly used measurement in that locale. For example
28507  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
28508  * the formatted number should be automatically converted to the most appropriate 
28509  * measure in the other system, in this case, mph. The formatted result should
28510  * appear as "37.3 mph". 
28511  * 
28512  * @abstract
28513  * @param {string} locale current locale string
28514  * @returns {ilib.Measurement} a new instance that is converted to locale
28515  */
28516 ilib.Measurement.Temperature.prototype.localize = function(locale) {
28517     var to;
28518     if (locale === "en-US" ) {
28519         to = ilib.Measurement.Temperature.metricToUScustomary[this.unit] || this.unit;
28520     } else {
28521         to = ilib.Measurement.Temperature.usCustomaryToMetric[this.unit] || this.unit;
28522     }
28523     return new ilib.Measurement.Temperature({
28524         unit: to,
28525         amount: this
28526     });
28527 };
28528 //register with the factory method
28529 ilib.Measurement._constructors["temperature"] = ilib.Measurement.Temperature;
28530 
28531 /*
28532  * Unknown.js - Dummy unit conversions for unknown types
28533  * 
28534  * Copyright © 2014, JEDLSoft
28535  *
28536  * Licensed under the Apache License, Version 2.0 (the "License");
28537  * you may not use this file except in compliance with the License.
28538  * You may obtain a copy of the License at
28539  *
28540  *     http://www.apache.org/licenses/LICENSE-2.0
28541  *
28542  * Unless required by applicable law or agreed to in writing, software
28543  * distributed under the License is distributed on an "AS IS" BASIS,
28544  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28545  *
28546  * See the License for the specific language governing permissions and
28547  * limitations under the License.
28548  */
28549 
28550 /*
28551 !depends 
28552 ilibglobal.js 
28553 unit.js
28554 */
28555 
28556 /**
28557  * @class
28558  * Create a new unknown measurement instance.
28559  * 
28560  * @constructor
28561  * @extends ilib.Measurement
28562  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
28563  * the construction of this instance
28564  */
28565 ilib.Measurement.Unknown = function (options) {
28566 	if (options) {
28567 		this.unit = options.unit;
28568 		this.amount = options.amount;
28569 	}
28570 };
28571 
28572 ilib.Measurement.Unknown.prototype = new ilib.Measurement({});
28573 ilib.Measurement.Unknown.prototype.parent = ilib.Measurement;
28574 ilib.Measurement.Unknown.prototype.constructor = ilib.Measurement.Unknown;
28575 
28576 ilib.Measurement.Unknown.aliases = {
28577 	"unknown":"unknown"
28578 };
28579 
28580 
28581 /**
28582  * Return the type of this measurement. Examples are "mass",
28583  * "length", "speed", etc. Measurements can only be converted
28584  * to measurements of the same type.<p>
28585  * 
28586  * The type of the units is determined automatically from the 
28587  * units. For example, the unit "grams" is type "mass". Use the 
28588  * static call {@link ilib.Measurement.getAvailableUnits}
28589  * to find out what units this version of ilib supports.
28590  *  
28591  * @return {string} the name of the type of this measurement
28592  */
28593 ilib.Measurement.Unknown.prototype.getMeasure = function() {
28594 	return "unknown";
28595 };
28596 
28597 /**
28598  * Return a new measurement instance that is converted to a new
28599  * measurement unit. Measurements can only be converted
28600  * to measurements of the same type.<p>
28601  *  
28602  * @param {string} to The name of the units to convert to
28603  * @return {ilib.Measurement|undefined} the converted measurement
28604  * or undefined if the requested units are for a different
28605  * measurement type 
28606  */
28607 ilib.Measurement.Unknown.prototype.convert = function(to) {
28608 	return undefined;
28609 };
28610 
28611 /**
28612  * Convert a unknown to another measure.
28613  * @static
28614  * @param {string} to unit to convert to
28615  * @param {string} from unit to convert from
28616  * @param {number} unknown amount to be convert
28617  * @returns {number|undefined} the converted amount
28618  */
28619 ilib.Measurement.Unknown.convert = function(to, from, unknown) {
28620     return undefined;
28621 };
28622 
28623 /**
28624  * Localize the measurement to the commonly used measurement in that locale. For example
28625  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
28626  * the formatted number should be automatically converted to the most appropriate 
28627  * measure in the other system, in this case, mph. The formatted result should
28628  * appear as "37.3 mph". 
28629  * 
28630  * @abstract
28631  * @param {string} locale current locale string
28632  * @returns {ilib.Measurement} a new instance that is converted to locale
28633  */
28634 ilib.Measurement.Unknown.prototype.localize = function(locale) {
28635     return new ilib.Measurement.Unknown({
28636         unit: this.unit,
28637         amount: this.amount
28638     });
28639 };
28640 
28641 /**
28642  * Scale the measurement unit to an acceptable level. The scaling
28643  * happens so that the integer part of the amount is as small as
28644  * possible without being below zero. This will result in the 
28645  * largest units that can represent this measurement without
28646  * fractions. Measurements can only be scaled to other measurements 
28647  * of the same type.
28648  * 
28649  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
28650  * or undefined if the system can be inferred from the current measure
28651  * @return {ilib.Measurement} a new instance that is scaled to the 
28652  * right level
28653  */
28654 ilib.Measurement.Unknown.prototype.scale = function(measurementsystem) {
28655     return new ilib.Measurement.Unknown({
28656         unit: this.unit,
28657         amount: this.amount
28658     }); 
28659 };
28660 
28661 /**
28662  * @private
28663  * @static
28664  */
28665 ilib.Measurement.Unknown.getMeasures = function () {
28666 	return [];
28667 };
28668 
28669 //register with the factory method
28670 ilib.Measurement._constructors["unknown"] = ilib.Measurement.Unknown;
28671 
28672 
28673 /*
28674  * Time.js - Unit conversions for Times/times
28675  * 
28676  * Copyright © 2014, JEDLSoft
28677  *
28678  * Licensed under the Apache License, Version 2.0 (the "License");
28679  * you may not use this file except in compliance with the License.
28680  * You may obtain a copy of the License at
28681  *
28682  *     http://www.apache.org/licenses/LICENSE-2.0
28683  *
28684  * Unless required by applicable law or agreed to in writing, software
28685  * distributed under the License is distributed on an "AS IS" BASIS,
28686  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28687  *
28688  * See the License for the specific language governing permissions and
28689  * limitations under the License.
28690  */
28691 
28692 /*
28693 !depends 
28694 ilibglobal.js 
28695 unit.js
28696 */
28697 
28698 /**
28699  * @class
28700  * Create a new time measurement instance.
28701  * 
28702  * @constructor
28703  * @extends ilib.Measurement
28704  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
28705  * the construction of this instance
28706  */
28707 ilib.Measurement.Time = function (options) {
28708 	this.unit = "ns";
28709 	this.amount = 0;
28710 	this.aliases = ilib.Measurement.Time.aliases; // share this table in all instances
28711 	
28712 	if (options) {
28713 		if (typeof(options.unit) !== 'undefined') {
28714 			this.originalUnit = options.unit;
28715 			this.unit = this.aliases[options.unit] || options.unit;
28716 		}
28717 		
28718 		if (typeof(options.amount) === 'object') {
28719 			if (options.amount.getMeasure() === "time") {
28720 				this.amount = ilib.Measurement.Time.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
28721 			} else {
28722 				throw "Cannot convert units " + options.amount.unit + " to a time";
28723 			}
28724 		} else if (typeof(options.amount) !== 'undefined') {
28725 			this.amount = parseFloat(options.amount);
28726 		}
28727 	}
28728 	
28729 	if (typeof(ilib.Measurement.Time.ratios[this.unit]) === 'undefined') {
28730 		throw "Unknown unit: " + options.unit;
28731 	}
28732 };
28733 
28734 ilib.Measurement.Time.ratios = {
28735 	/*              index  nsec        msec        mlsec       sec        min          hour          day           week         month        year         decade        century    */           
28736 	"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  ],  
28737 	"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  ],  
28738 	"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  ],
28739 	"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  ],
28740 	"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   ],
28741     "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   ],
28742     "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   ],
28743     "week":         [ 8,   6.048e+14,  6.048e+11,  6.048e+8,   604800,    10080,       168,          7,            1,           0.229984,    0.0191654,   0.00191654,   0.000191654 ],
28744     "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 ],
28745     "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        ],
28746     "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         ],
28747     "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           ]
28748 };
28749 
28750 ilib.Measurement.Time.prototype = new ilib.Measurement({});
28751 ilib.Measurement.Time.prototype.parent = ilib.Measurement;
28752 ilib.Measurement.Time.prototype.constructor = ilib.Measurement.Time;
28753 
28754 /**
28755  * Return the type of this measurement. Examples are "mass",
28756  * "length", "speed", etc. Measurements can only be converted
28757  * to measurements of the same type.<p>
28758  * 
28759  * The type of the units is determined automatically from the 
28760  * units. For example, the unit "grams" is type "mass". Use the 
28761  * static call {@link ilib.Measurement.getAvailableUnits}
28762  * to find out what units this version of ilib supports.
28763  *  
28764  * @return {string} the name of the type of this measurement
28765  */
28766 ilib.Measurement.Time.prototype.getMeasure = function() {
28767 	return "time";
28768 };
28769 
28770 /**
28771  * Return a new measurement instance that is converted to a new
28772  * measurement unit. Measurements can only be converted
28773  * to measurements of the same type.<p>
28774  *  
28775  * @param {string} to The name of the units to convert to
28776  * @return {ilib.Measurement|undefined} the converted measurement
28777  * or undefined if the requested units are for a different
28778  * measurement type 
28779  */
28780 ilib.Measurement.Time.prototype.convert = function(to) {
28781 	if (!to || typeof(ilib.Measurement.Time.ratios[this.normalizeUnits(to)]) === 'undefined') {
28782 		return undefined;
28783 	}
28784 	return new ilib.Measurement({
28785 		unit: to,
28786 		amount: this
28787 	});
28788 };
28789 
28790 ilib.Measurement.Time.aliases = {
28791     "ns": "nanosecond",
28792     "NS": "nanosecond",
28793     "nS": "nanosecond",
28794     "Ns": "nanosecond",
28795     "Nanosecond": "nanosecond",
28796     "Nanoseconds": "nanosecond",
28797     "nanosecond": "nanosecond",
28798     "nanoseconds": "nanosecond",
28799     "NanoSecond": "nanosecond",
28800     "NanoSeconds": "nanosecond",
28801     "μs": "microsecond",
28802     "μS": "microsecond",
28803     "microsecond": "microsecond",
28804     "microseconds": "microsecond",
28805     "Microsecond": "microsecond",
28806     "Microseconds": "microsecond",
28807     "MicroSecond": "microsecond",
28808     "MicroSeconds": "microsecond",
28809     "ms": "millisecond",
28810     "MS": "millisecond",
28811     "mS": "millisecond",
28812     "Ms": "millisecond",
28813     "millisecond": "millisecond",
28814     "milliseconds": "millisecond",
28815     "Millisecond": "millisecond",
28816     "Milliseconds": "millisecond",
28817     "MilliSecond": "millisecond",
28818     "MilliSeconds": "millisecond",
28819     "s": "second",
28820     "S": "second",
28821     "sec": "second",
28822     "second": "second",
28823     "seconds": "second",
28824     "Second": "second",
28825     "Seconds": "second",
28826     "min": "minute",
28827     "Min": "minute",
28828     "minute": "minute",
28829     "minutes": "minute",
28830     "Minute": "minute",
28831     "Minutes": "minute",
28832     "h": "hour",
28833     "H": "hour",
28834     "hr": "hour",
28835     "Hr": "hour",
28836     "hR": "hour",
28837     "HR": "hour",
28838     "hour": "hour",
28839     "hours": "hour",
28840     "Hour": "hour",
28841     "Hours": "hour",
28842     "Hrs": "hour",
28843     "hrs": "hour",
28844     "day": "day",
28845     "days": "day",
28846     "Day": "day",
28847     "Days": "day",
28848     "week": "week",
28849     "weeks": "week",
28850     "Week": "week",
28851     "Weeks": "week",
28852     "month": "month",
28853     "Month": "month",
28854     "months": "month",
28855     "Months": "month",
28856     "year": "year",
28857     "years": "year",
28858     "Year": "year",
28859     "Years": "year",
28860     "yr": "year",
28861     "Yr": "year",
28862     "yrs": "year",
28863     "Yrs": "year",
28864     "decade": "decade",
28865     "decades": "decade",
28866     "Decade": "decade",
28867     "Decades": "decade",
28868     "century": "century",
28869     "centuries": "century",
28870     "Century": "century",
28871     "Centuries": "century"
28872 };
28873 
28874 /**
28875  * Convert a time to another measure.
28876  * @static
28877  * @param to {string} unit to convert to
28878  * @param from {string} unit to convert from
28879  * @param time {number} amount to be convert
28880  * @returns {number|undefined} the converted amount
28881  */
28882 ilib.Measurement.Time.convert = function(to, from, time) {
28883     from = ilib.Measurement.Time.aliases[from] || from;
28884     to = ilib.Measurement.Time.aliases[to] || to;
28885     var fromRow = ilib.Measurement.Time.ratios[from];
28886     var toRow = ilib.Measurement.Time.ratios[to];
28887     if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
28888         return undefined;
28889     }	
28890     return time * fromRow[toRow[0]];
28891 };
28892 
28893 /**
28894  * Localize the measurement to the commonly used measurement in that locale. For example
28895  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
28896  * the formatted number should be automatically converted to the most appropriate 
28897  * measure in the other system, in this case, mph. The formatted result should
28898  * appear as "37.3 mph". 
28899  * 
28900  * @abstract
28901  * @param {string} locale current locale string
28902  * @returns {ilib.Measurement} a new instance that is converted to locale
28903  */
28904 ilib.Measurement.Time.prototype.localize = function(locale) {
28905     return new ilib.Measurement.Time({
28906         unit: this.unit,
28907         amount: this.amount
28908     });
28909 };
28910 
28911 /**
28912  * Scale the measurement unit to an acceptable level. The scaling
28913  * happens so that the integer part of the amount is as small as
28914  * possible without being below zero. This will result in the 
28915  * largest units that can represent this measurement without
28916  * fractions. Measurements can only be scaled to other measurements 
28917  * of the same type.
28918  * 
28919  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
28920  * or undefined if the system can be inferred from the current measure
28921  * @return {ilib.Measurement} a new instance that is scaled to the 
28922  * right level
28923  */
28924 ilib.Measurement.Time.prototype.scale = function(measurementsystem) {
28925 
28926     var fromRow = ilib.Measurement.Time.ratios[this.unit];
28927     var time = this.amount;
28928     var munit = this.unit;
28929     var i=1;
28930 
28931     for (var m in ilib.Measurement.Time.ratios) {
28932         var tmp = this.amount * fromRow[i];
28933         if (tmp < 1) break;
28934         time = tmp;
28935         munit = m;
28936         ++i
28937     }
28938 
28939     return new ilib.Measurement.Time({
28940         unit: munit,
28941         amount: time
28942     });
28943 };
28944 /**
28945  * @private
28946  * @static
28947  */
28948 ilib.Measurement.Time.getMeasures = function () {
28949 	var ret = [];
28950 	for (var m in ilib.Measurement.Time.ratios) {
28951 		ret.push(m);
28952 	}
28953 	return ret;
28954 };
28955 
28956 //register with the factory method
28957 ilib.Measurement._constructors["time"] = ilib.Measurement.Time;
28958 
28959 /*
28960  * Mass.js - Unit conversions for Mass/mass
28961  * 
28962  * Copyright © 2014, JEDLSoft
28963  *
28964  * Licensed under the Apache License, Version 2.0 (the "License");
28965  * you may not use this file except in compliance with the License.
28966  * You may obtain a copy of the License at
28967  *
28968  *     http://www.apache.org/licenses/LICENSE-2.0
28969  *
28970  * Unless required by applicable law or agreed to in writing, software
28971  * distributed under the License is distributed on an "AS IS" BASIS,
28972  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28973  *
28974  * See the License for the specific language governing permissions and
28975  * limitations under the License.
28976  */
28977 
28978 /*
28979 !depends 
28980 ilibglobal.js 
28981 */
28982 
28983 /**
28984  * @class
28985  * Create a new mass measurement instance.
28986  *
28987  * @constructor
28988  * @extends ilib.Measurement
28989  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
28990  * the construction of this instance
28991  */
28992 ilib.Measurement.Mass = function (options) {
28993 	this.unit = "ns";
28994 	this.amount = 0;
28995 	this.aliases = ilib.Measurement.Mass.aliases; // share this table in all instances
28996 	
28997 	if (options) {
28998 		if (typeof(options.unit) !== 'undefined') {
28999 			this.originalUnit = options.unit;
29000 			this.unit = this.aliases[options.unit] || options.unit;
29001 		}
29002 		
29003 		if (typeof(options.amount) === 'object') {
29004 			if (options.amount.getMeasure() === "mass") {
29005 				this.amount = ilib.Measurement.Mass.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
29006 			} else {
29007 				throw "Cannot convert units " + options.amount.unit + " to a mass";
29008 			}
29009 		} else if (typeof(options.amount) !== 'undefined') {
29010 			this.amount = parseFloat(options.amount);
29011 		}
29012 	}
29013 	
29014 	if (typeof(ilib.Measurement.Mass.ratios[this.unit]) === 'undefined') {
29015 		throw "Unknown unit: " + options.unit;
29016 	}
29017 };
29018 
29019 ilib.Measurement.Mass.ratios = {
29020 	/*             index  µg          mg         g          oz          lp           kg          st            sh ton       mt ton        ln ton      */           
29021 	"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   ],  
29022 	"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   ],  
29023 	"gram":        [ 3,   1e+6,       1000,      1,         0.035274,   0.00220462,  0.001,      0.000157473,  1.1023e-6,   1e-6,         9.8421e-7    ],
29024 	"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    ],
29025 	"pound":       [ 5,   4.536e+8,   453592,    453.592,   16,         1,           0.453592,   0.0714286,    0.0005,      0.000453592,  0.000446429  ],
29026     "kilogram":    [ 6,   1e+9,       1e+6,      1000,      35.274,     2.20462,     1,          0.157473,     0.00110231,  0.001,        0.000984207  ],
29027     "stone":       [ 7,   6.35e+9,    6.35e+6,   6350.29,   224,        14,          6.35029,    1,            0.007,       0.00635029,   0.00625      ],
29028     "short ton":   [ 8,   9.072e+11,  9.072e+8,  907185,    32000,      2000,        907.185,    142.857,      1,           0.907185,     0.892857     ],
29029     "metric ton":  [ 9,   1e+12,      1e+9,      1e+6,      35274,      2204.62,     1000,       157.473,      1.10231,     1,            0.984207     ],
29030     "long ton":    [ 10,  1.016e+12,  1.016e+9,  1.016e+6,  35840,      2240,        1016.05,    160,          1.12,        1.01605,      1            ]
29031 };
29032 
29033 ilib.Measurement.Mass.metricSystem = {
29034     "microgram": 1,
29035     "milligram": 2,
29036     "gram": 3,
29037     "kilogram": 6,
29038     "metric ton": 9
29039 };
29040 ilib.Measurement.Mass.imperialSystem = {
29041     "ounce": 4,
29042     "pound": 5,
29043     "stone": 7,
29044     "long ton": 10
29045 };
29046 ilib.Measurement.Mass.uscustomarySystem = {
29047     "ounce": 4,
29048     "pound": 5,
29049     "short ton": 8
29050 };
29051 
29052 ilib.Measurement.Mass.metricToUScustomary = {
29053     "microgram": "ounce",
29054     "milligram": "ounce",
29055     "gram": "ounce",
29056     "kilogram": "pound",
29057     "metric ton": "long ton"
29058 };
29059 ilib.Measurement.Mass.metricToImperial = {
29060     "microgram": "ounce",
29061     "milligram": "ounce",
29062     "gram": "ounce",
29063     "kilogram": "pound",
29064     "metric ton": "short ton"
29065 };
29066 
29067 ilib.Measurement.Mass.imperialToMetric = {
29068     "ounce": "gram",
29069     "pound": "kilogram",
29070     "stone": "kilogram",
29071     "short ton": "metric ton"
29072 };
29073 ilib.Measurement.Mass.imperialToUScustomary = {
29074     "ounce": "ounce",
29075     "pound": "pound",
29076     "stone": "stone",
29077     "short ton": "long ton"
29078 };
29079 
29080 ilib.Measurement.Mass.uScustomaryToImperial = {
29081     "ounce": "ounce",
29082     "pound": "pound",
29083     "stone": "stone",
29084     "long ton": "short ton"
29085 };
29086 ilib.Measurement.Mass.uScustomarylToMetric = {
29087     "ounce": "gram",
29088     "pound": "kilogram",
29089     "stone": "kilogram",
29090     "long ton": "metric ton"
29091 };
29092 
29093 
29094 ilib.Measurement.Mass.prototype = new ilib.Measurement({});
29095 ilib.Measurement.Mass.prototype.parent = ilib.Measurement;
29096 ilib.Measurement.Mass.prototype.constructor = ilib.Measurement.Mass;
29097 
29098 /**
29099  * Localize the measurement to the commonly used measurement in that locale. For example
29100  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
29101  * the formatted number should be automatically converted to the most appropriate 
29102  * measure in the other system, in this case, mph. The formatted result should
29103  * appear as "37.3 mph". 
29104  * 
29105  * @abstract
29106  * @param {string} locale current locale string
29107  * @returns {ilib.Measurement} a new instance that is converted to locale
29108  */
29109 ilib.Measurement.Mass.prototype.localize = function(locale) {
29110 	var to;
29111 	if (locale === "en-US") {
29112 		to = ilib.Measurement.Mass.metricToUScustomary[this.unit] ||
29113 		    ilib.Measurement.Mass.imperialToUScustomary[this.unit] || this.unit;
29114 	} else if (locale === "en-GB") {
29115 		to = ilib.Measurement.Mass.metricToImperial[this.unit] ||
29116 		    ilib.Measurement.Mass.uScustomaryToImperial[this.unit] || this.unit;
29117 	} else {
29118 		to = ilib.Measurement.Mass.uScustomarylToMetric[this.unit] ||
29119 		    ilib.Measurement.Mass.imperialToUScustomary[this.unit] || this.unit;
29120 	}
29121 	return new ilib.Measurement.Mass({
29122 	    unit: to,
29123 	    amount: this
29124 	});
29125 };
29126 
29127 /**
29128  * Return the type of this measurement. Examples are "mass",
29129  * "length", "speed", etc. Measurements can only be converted
29130  * to measurements of the same type.<p>
29131  * 
29132  * The type of the units is determined automatically from the 
29133  * units. For example, the unit "grams" is type "mass". Use the 
29134  * static call {@link ilib.Measurement.getAvailableUnits}
29135  * to find out what units this version of ilib supports.
29136  *  
29137  * @return {string} the name of the type of this measurement
29138  */
29139 ilib.Measurement.Mass.prototype.getMeasure = function() {
29140 	return "mass";
29141 };
29142 
29143 /**
29144  * Return a new measurement instance that is converted to a new
29145  * measurement unit. Measurements can only be converted
29146  * to measurements of the same type.<p>
29147  *  
29148  * @param {string} to The name of the units to convert to
29149  * @return {ilib.Measurement|undefined} the converted measurement
29150  * or undefined if the requested units are for a different
29151  * measurement type 
29152  */
29153 ilib.Measurement.Mass.prototype.convert = function(to) {
29154 	if (!to || typeof(ilib.Measurement.Mass.ratios[this.normalizeUnits(to)]) === 'undefined') {
29155 		return undefined;
29156 	}
29157 	return new ilib.Measurement({
29158 		unit: to,
29159 		amount: this
29160 	});
29161 };
29162 
29163 ilib.Measurement.Mass.aliases = {
29164     "µg":"microgram",
29165     "microgram":"microgram",
29166     "mcg":"microgram",  
29167     "milligram":"milligram",
29168     "mg":"milligram",
29169     "milligrams":"milligram",
29170     "Milligram":"milligram",
29171     "Milligrams":"milligram",
29172     "MilliGram":"milligram",
29173     "MilliGrams":"milligram",
29174     "g":"gram",
29175     "gram":"gram",
29176     "grams":"gram",
29177     "Gram":"gram",
29178     "Grams":"gram",
29179     "ounce":"ounce",
29180     "oz":"ounce",
29181     "Ounce":"ounce",
29182     "℥":"ounce",
29183     "pound":"pound",
29184     "poundm":"pound",
29185     "℔":"pound",
29186     "lb":"pound",
29187     "pounds":"pound",
29188     "Pound":"pound",
29189     "Pounds":"pound",
29190     "kilogram":"kilogram",
29191     "kg":"kilogram",
29192     "kilograms":"kilogram",
29193     "kilo grams":"kilogram",
29194     "kilo gram":"kilogram",
29195     "Kilogram":"kilogram",    
29196     "Kilograms":"kilogram",
29197     "KiloGram":"kilogram",
29198     "KiloGrams":"kilogram",
29199     "Kilo gram":"kilogram",
29200     "Kilo grams":"kilogram",
29201     "Kilo Gram":"kilogram",
29202     "Kilo Grams":"kilogram",
29203     "stone":"stone",
29204     "st":"stone",
29205     "stones":"stone",
29206     "Stone":"stone",
29207     "short ton":"short ton",
29208     "Short ton":"short ton",
29209     "Short Ton":"short ton",
29210     "metric ton":"metric ton",
29211     "metricton":"metric ton",
29212     "t":"metric ton",
29213     "tonne":"metric ton",
29214     "Tonne":"metric ton",
29215     "Metric Ton":"metric ton",
29216     "MetricTon":"metric ton",    
29217     "long ton":"long ton",
29218     "longton":"long ton",
29219     "Longton":"long ton",
29220     "Long ton":"long ton",
29221     "Long Ton":"long ton",
29222     "ton":"long ton",
29223     "Ton":"long ton"
29224 };
29225 
29226 /**
29227  * Convert a mass to another measure.
29228  * @static
29229  * @param to {string} unit to convert to
29230  * @param from {string} unit to convert from
29231  * @param mass {number} amount to be convert
29232  * @returns {number|undefined} the converted amount
29233  */
29234 ilib.Measurement.Mass.convert = function(to, from, mass) {
29235     from = ilib.Measurement.Mass.aliases[from] || from;
29236     to = ilib.Measurement.Mass.aliases[to] || to;
29237     var fromRow = ilib.Measurement.Mass.ratios[from];
29238     var toRow = ilib.Measurement.Mass.ratios[to];
29239     if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
29240         return undefined;
29241     }	
29242     return mass * fromRow[toRow[0]];    
29243 };
29244 
29245 /**
29246  * Scale the measurement unit to an acceptable level. The scaling
29247  * happens so that the integer part of the amount is as small as
29248  * possible without being below zero. This will result in the 
29249  * largest units that can represent this measurement without
29250  * fractions. Measurements can only be scaled to other measurements 
29251  * of the same type.
29252  * 
29253  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
29254  * or undefined if the system can be inferred from the current measure
29255  * @return {ilib.Measurement} a new instance that is scaled to the 
29256  * right level
29257  */
29258 ilib.Measurement.Mass.prototype.scale = function(measurementsystem) {
29259     var mSystem;    
29260     if (measurementsystem === "metric" || (typeof(measurementsystem) === 'undefined' 
29261             && typeof(ilib.Measurement.Mass.metricSystem[this.unit]) !== 'undefined')) {
29262         mSystem = ilib.Measurement.Mass.metricSystem;
29263     } else if (measurementsystem === "imperial" || (typeof(measurementsystem) === 'undefined' 
29264             && typeof(ilib.Measurement.Mass.imperialSystem[this.unit]) !== 'undefined')) {
29265         mSystem = ilib.Measurement.Mass.imperialSystem;
29266     } else if (measurementsystem === "uscustomary" || (typeof(measurementsystem) === 'undefined' 
29267             && typeof(ilib.Measurement.Mass.uscustomarySystem[this.unit]) !== 'undefined')) {
29268         mSystem = ilib.Measurement.Mass.uscustomarySystem;
29269     } else {
29270         return new ilib.Measurement.Mass({
29271 			unit: this.unit,
29272 			amount: this.amount
29273 		});
29274     }    
29275     
29276     var mass = this.amount;
29277     var munit = this.amount;
29278     var fromRow = ilib.Measurement.Mass.ratios[this.unit];
29279     
29280     for (var m in mSystem) {
29281         var tmp = this.amount * fromRow[mSystem[m]];
29282         if (tmp < 1) break;
29283         mass = tmp;
29284         munit = m;
29285     }
29286     
29287     return new ilib.Measurement.Mass({
29288 		unit: munit,
29289 		amount: mass
29290     });
29291 };
29292 
29293 /**
29294  * @private
29295  * @static
29296  */
29297 ilib.Measurement.Mass.getMeasures = function () {
29298 	var ret = [];
29299 	for (var m in ilib.Measurement.Mass.ratios) {
29300 		ret.push(m);
29301 	}
29302 	return ret;
29303 };
29304 
29305 //register with the factory method
29306 ilib.Measurement._constructors["mass"] = ilib.Measurement.Mass;
29307 
29308 /*
29309  * area.js - Unit conversions for Area
29310  * 
29311  * Copyright © 2014, JEDLSoft
29312  *
29313  * Licensed under the Apache License, Version 2.0 (the "License");
29314  * you may not use this file except in compliance with the License.
29315  * You may obtain a copy of the License at
29316  *
29317  *     http://www.apache.org/licenses/LICENSE-2.0
29318  *
29319  * Unless required by applicable law or agreed to in writing, software
29320  * distributed under the License is distributed on an "AS IS" BASIS,
29321  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29322  *
29323  * See the License for the specific language governing permissions and
29324  * limitations under the License.
29325  */
29326 
29327 /*
29328 !depends 
29329 ilibglobal.js
29330 unit.js
29331 */
29332 
29333 /**
29334  * @class
29335  * Create a new area measurement instance.
29336  * @constructor
29337  * @extends ilib.Measurement
29338  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
29339  * the construction of this instance
29340  */
29341 ilib.Measurement.Area = function (options) {
29342 	this.unit = "square km";
29343 	this.amount = 0;
29344 	this.aliases = ilib.Measurement.Area.aliases; // share this table in all instances
29345 	
29346 	if (options) {
29347 		if (typeof(options.unit) !== 'undefined') {
29348 			this.originalUnit = options.unit;
29349 			this.unit = this.aliases[options.unit] || options.unit;
29350 		}
29351 		
29352 		if (typeof(options.amount) === 'object') {
29353 			if (options.amount.getMeasure() === "area") {
29354 				this.amount = ilib.Measurement.Area.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
29355 			} else {
29356 				throw "Cannot convert unit " + options.amount.unit + " to area";
29357 			}
29358 		} else if (typeof(options.amount) !== 'undefined') {
29359 			this.amount = parseFloat(options.amount);
29360 		}
29361 	}
29362 	
29363 	if (typeof(ilib.Measurement.Area.ratios[this.unit]) === 'undefined') {
29364 		throw "Unknown unit: " + options.unit;
29365 	}
29366 };
29367 
29368 ilib.Measurement.Area.ratios = {
29369     /*               index		square cm,		square meter,   hectare,   	square km, 	, square inch 	square foot, 		square yard, 	  	  		acre,			square mile			        */
29370     "square centimeter":[1,   	1,				0.0001,			1e-8,	    1e-10,        0.15500031,	0.00107639104,		0.000119599005,			2.47105381e-8,		3.86102159e-11 		],
29371     "square meter": 	[2,   	10000,			1,              1e-4,       1e-6,         1550,    	 	10.7639,    	  	1.19599,   				0.000247105,		3.861e-7     	    ],
29372     "hectare":      	[3,	 	100000000,  	10000,          1,          0.01,         1.55e+7, 	  	107639,     	 	11959.9,   				2.47105	,			0.00386102    	    ],
29373     "square km":    	[4,	  	10000000000, 	1e+6,          	100,        1,	          1.55e+9, 	  	1.076e+7,   	 	1.196e+6,  				247.105 ,   		0.386102     	    ],
29374     "square inch":  	[5,	  	6.4516,			0.00064516,     6.4516e-8,  6.4516e-10,   1,			0.000771605,	  	0.0007716051, 			1.5942e-7,			2.491e-10    	    ],
29375     "square foot":  	[6,		929.0304,		0.092903,       9.2903e-6,  9.2903e-8,    144,			1,          	  	0.111111,  				2.2957e-5,			3.587e-8    		],
29376     "square yard":  	[7,		8361.2736,		0.836127,       8.3613e-5,  8.3613e-7,    1296,    	  	9,          	  	1,         				0.000206612,		3.2283e-7    	    ],
29377     "acre":         	[8,		40468564.2,		4046.86,        0.404686,   0.00404686,   6.273e+6,	  	43560,      	  	4840,      				1,		    		0.0015625    	    ],
29378     "square mile":  	[9,	   	2.58998811e+10,	2.59e+6,        258.999,    2.58999,      4.014e+9,	 	2.788e+7,   	  	3.098e+6,  				640,     			1   	     		]
29379 }
29380 
29381 ilib.Measurement.Area.prototype = new ilib.Measurement({});
29382 ilib.Measurement.Area.prototype.parent = ilib.Measurement;
29383 ilib.Measurement.Area.prototype.constructor = ilib.Measurement.Area;
29384 
29385 /**
29386  * Return the type of this measurement. Examples are "mass",
29387  * "length", "speed", etc. Measurements can only be converted
29388  * to measurements of the same type.<p>
29389  * 
29390  * The type of the units is determined automatically from the 
29391  * units. For example, the unit "grams" is type "mass". Use the 
29392  * static call {@link ilib.Measurement.getAvailableUnits}
29393  * to find out what units this version of ilib supports.
29394  *  
29395  * @return {string} the name of the type of this measurement
29396  */
29397 ilib.Measurement.Area.prototype.getMeasure = function() {
29398 	return "area";
29399 }; 
29400 
29401 /**
29402  * Return a new measurement instance that is converted to a new
29403  * measurement unit. Measurements can only be converted
29404  * to measurements of the same type.<p>
29405  *  
29406  * @param {string} to The name of the units to convert to
29407  * @return {ilib.Measurement|undefined} the converted measurement
29408  * or undefined if the requested units are for a different
29409  * measurement type
29410  * 
29411  */
29412 ilib.Measurement.Area.prototype.convert = function(to) {
29413 	if (!to || typeof(ilib.Measurement.Area.ratios[this.normalizeUnits(to)]) === 'undefined') {
29414 		return undefined;
29415 	}
29416 	return new ilib.Measurement({
29417 		unit: to, 
29418 		amount: this
29419 	});
29420 };
29421 
29422 ilib.Measurement.Area.aliases = {
29423     "square centimeter":"square centimeter",
29424     "square cm":"square centimeter",
29425     "sq cm":"square centimeter",
29426     "Square Cm":"square centimeter",
29427     "square Centimeters":"square centimeter",
29428     "square Centimeter":"square centimeter",
29429     "square Centimetre":"square centimeter",
29430     "square Centimetres":"square centimeter",
29431     "square centimeters":"square centimeter",
29432     "Square km": "square km",
29433 	"Square kilometre":"square km",
29434 	"square kilometer":"square km",
29435 	"square kilometre":"square km",
29436 	"square kilometers":"square km",
29437 	"square kilometres":"square km",
29438         "square km":"square km",
29439 	"sq km":"square km",
29440 	"km2":"square km",
29441 	"Hectare":"hectare",
29442 	"hectare":"hectare",
29443 	"ha":"hectare",
29444 	"Square meter": "square meter",
29445 	"Square meters":"square meter",
29446 	"square meter": "square meter",
29447 	"square meters":"square meter",
29448 	"Square metre": "square meter",
29449 	"Square metres":"square meter",
29450 	"square metres": "square meter",
29451 	"Square Metres":"square meter",
29452 	"sqm":"square meter",
29453 	"m2": "square meter",
29454 	"Square mile":"square mile",
29455 	"Square miles":"square mile",
29456 	"square mile":"square mile",
29457 	"square miles":"square mile",
29458 	"square mi":"square mile",
29459 	"Square mi":"square mile",
29460 	"sq mi":"square mile",
29461 	"mi2":"square mile",
29462 	"Acre": "acre",
29463 	"acre": "acre",
29464 	"Acres":"acre",
29465 	"acres":"acre",
29466 	"Square yard": "square yard",
29467 	"Square yards":"square yard",
29468 	"square yard": "square yard",
29469 	"square yards":"square yard",
29470 	"yd2":"square yard",
29471 	"Square foot": "square foot",
29472 	"square foot": "square foot",
29473 	"Square feet": "square foot",
29474 	"Square Feet": "square foot",
29475 	"sq ft":"square foot",
29476 	"ft2":"square foot",
29477 	"Square inch":"square inch",
29478 	"square inch":"square inch",
29479 	"Square inches":"square inch",
29480 	"square inches":"square inch",
29481 	"in2":"square inch"
29482 };
29483 
29484 /**
29485  * Convert a Area to another measure.
29486  * @static
29487  * @param to {string} unit to convert to
29488  * @param from {string} unit to convert from
29489  * @param area {number} amount to be convert
29490  * @returns {number|undefined} the converted amount
29491  */
29492 ilib.Measurement.Area.convert = function(to, from, area) {
29493     from = ilib.Measurement.Area.aliases[from] || from;
29494     to = ilib.Measurement.Area.aliases[to] || to;
29495 	var fromRow = ilib.Measurement.Area.ratios[from];
29496 	var toRow = ilib.Measurement.Area.ratios[to];
29497 	if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
29498 		return undefined;
29499 	}
29500 	return area* fromRow[toRow[0]];
29501 };
29502 
29503 /**
29504  * @private
29505  * @static
29506  */
29507 ilib.Measurement.Area.getMeasures = function () {
29508 	var ret = [];
29509 	for (var m in ilib.Measurement.Area.ratios) {
29510 		ret.push(m);
29511 	}
29512 	return ret;
29513 };
29514 
29515 ilib.Measurement.Area.metricSystem = {
29516 	"square centimeter" : 1,
29517 	"square meter" : 2,
29518 	"hectare" : 3,
29519 	"square km" : 4
29520 };
29521 ilib.Measurement.Area.imperialSystem = {
29522 	"square inch" : 5,
29523 	"square foot" : 6,
29524 	"square yard" : 7,
29525 	"acre" : 8,
29526 	"square mile" : 9
29527 };
29528 ilib.Measurement.Area.uscustomarySystem = {
29529 	"square inch" : 5,
29530 	"square foot" : 6,
29531 	"square yard" : 7,
29532 	"acre" : 8,
29533 	"square mile" : 9
29534 };
29535 
29536 ilib.Measurement.Area.metricToUScustomary = {
29537 	"square centimeter" : "square inch",
29538 	"square meter" : "square yard",
29539 	"hectare" : "acre",
29540 	"square km" : "square mile"
29541 };
29542 ilib.Measurement.Area.usCustomaryToMetric = {
29543 	"square inch" : "square centimeter",
29544 	"square foot" : "square meter",
29545 	"square yard" : "square meter",
29546 	"acre" : "hectare",
29547 	"square mile" : "square km"
29548 };
29549 
29550 
29551 /**
29552  * Scale the measurement unit to an acceptable level. The scaling
29553  * happens so that the integer part of the amount is as small as
29554  * possible without being below zero. This will result in the 
29555  * largest units that can represent this measurement without
29556  * fractions. Measurements can only be scaled to other measurements 
29557  * of the same type.
29558  * 
29559  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
29560  * or undefined if the system can be inferred from the current measure
29561  * @return {ilib.Measurement} a new instance that is scaled to the 
29562  * right level
29563  */
29564 ilib.Measurement.Area.prototype.scale = function(measurementsystem) {
29565     var fromRow = ilib.Measurement.Area.ratios[this.unit];
29566     var mSystem;
29567 
29568     if (measurementsystem === "metric" || (typeof(measurementsystem) === 'undefined'
29569         && typeof(ilib.Measurement.Area.metricSystem[this.unit]) !== 'undefined')) {
29570         mSystem = ilib.Measurement.Area.metricSystem;
29571     }
29572 
29573     else  if (measurementsystem === "uscustomary" || (typeof(measurementsystem) === 'undefined'
29574         && typeof(ilib.Measurement.Area.metricSystem[this.unit]) !== 'undefined')) {
29575         mSystem = ilib.Measurement.Area.uscustomarySystem;
29576     }
29577 
29578     else if (measurementsystem === "imperial" || (typeof(measurementsystem) === 'undefined'
29579         && typeof(ilib.Measurement.Area.metricSystem[this.unit]) !== 'undefined')) {
29580         mSystem = ilib.Measurement.Area.imperialSystem;
29581     }
29582 
29583     var area = this.amount;
29584     var munit = this.unit;
29585 
29586     for (var m in mSystem) {
29587         var tmp = this.amount * fromRow[mSystem[m]];
29588         if (tmp < 1) break;
29589         area = tmp;
29590         munit = m;
29591     }
29592 
29593     return new ilib.Measurement.Area({
29594         unit: munit,
29595         amount: area
29596     });
29597 };
29598 
29599 /**
29600  * Localize the measurement to the commonly used measurement in that locale. For example
29601  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
29602  * the formatted number should be automatically converted to the most appropriate 
29603  * measure in the other system, in this case, mph. The formatted result should
29604  * appear as "37.3 mph". 
29605  * 
29606  * @abstract
29607  * @param {string} locale current locale string
29608  * @returns {ilib.Measurement} a new instance that is converted to locale
29609  */
29610 ilib.Measurement.Area.prototype.localize = function(locale) {
29611     var to;
29612     if (locale === "en-US" || locale === "en-GB") {
29613         to = ilib.Measurement.Area.metricToUScustomary[this.unit] || this.unit;
29614     } else {
29615         to = ilib.Measurement.Area.usCustomaryToMetric[this.unit] || this.unit;
29616     }
29617     return new ilib.Measurement.Area({
29618         unit: to,
29619         amount: this
29620     });
29621 };
29622 
29623 
29624 //register with the factory method
29625 ilib.Measurement._constructors["area"] = ilib.Measurement.Area;
29626 
29627 /*
29628  * fuelconsumption.js - Unit conversions for FuelConsumption
29629  *
29630  * Copyright © 2014, JEDLSoft
29631  *
29632  * Licensed under the Apache License, Version 2.0 (the "License");
29633  * you may not use this file except in compliance with the License.
29634  * You may obtain a copy of the License at
29635  *
29636  *     http://www.apache.org/licenses/LICENSE-2.0
29637  *
29638  * Unless required by applicable law or agreed to in writing, software
29639  * distributed under the License is distributed on an "AS IS" BASIS,
29640  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29641  *
29642  * See the License for the specific language governing permissions and
29643  * limitations under the License.
29644  */
29645 /*
29646 !depends 
29647 ilibglobal.js 
29648 */
29649 /**
29650  * @class
29651  * Create a new fuelconsumption measurement instance.
29652  * 
29653  * @constructor
29654  * @extends ilib.Measurement
29655  * @param options {{unit:string,amount:number|string|undefined}} Options controlling
29656  * the construction of this instance
29657  */
29658 ilib.Measurement.FuelConsumption = function(options) {
29659     this.unit = "km/liter";
29660     this.amount = 0;
29661     this.aliases = ilib.Measurement.FuelConsumption.aliases; // share this table in all instances
29662 
29663     if (options) {
29664         if (typeof(options.unit) !== 'undefined') {
29665             this.originalUnit = options.unit;
29666             this.unit = this.aliases[options.unit] || options.unit;
29667         }
29668 
29669         if (typeof(options.amount) === 'object') {
29670             if (options.amount.getMeasure() === "fuelconsumption") {
29671                 this.amount = ilib.Measurement.FuelConsumption.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
29672             } else {
29673                 throw "Cannot convert unit " + options.amount.unit + " to fuelconsumption";
29674             }
29675         } else if (typeof(options.amount) !== 'undefined') {
29676             this.amount = parseFloat(options.amount);
29677         }
29678     }
29679 };
29680 
29681 
29682 ilib.Measurement.FuelConsumption.ratios = [
29683     "km/liter",
29684     "liter/100km",
29685     "mpg",
29686     "mpg(imp)"
29687 ];
29688 
29689 ilib.Measurement.FuelConsumption.prototype = new ilib.Measurement({});
29690 ilib.Measurement.FuelConsumption.prototype.parent = ilib.Measurement;
29691 ilib.Measurement.FuelConsumption.prototype.constructor = ilib.Measurement.FuelConsumption;
29692 
29693 /**
29694  * Return the type of this measurement. Examples are "mass",
29695  * "length", "speed", etc. Measurements can only be converted
29696  * to measurements of the same type.<p>
29697  * 
29698  * The type of the units is determined automatically from the 
29699  * units. For example, the unit "grams" is type "mass". Use the 
29700  * static call {@link ilib.Measurement.getAvailableUnits}
29701  * to find out what units this version of ilib supports.
29702  *  
29703  * @return {string} the name of the type of this measurement
29704  */
29705 ilib.Measurement.FuelConsumption.prototype.getMeasure = function() {
29706     return "fuelconsumption";
29707 };
29708 
29709 /**
29710  * Return a new measurement instance that is converted to a new
29711  * measurement unit. Measurements can only be converted
29712  * to measurements of the same type.<p>
29713  *  
29714  * @param {string} to The name of the units to convert to
29715  * @return {ilib.Measurement|undefined} the converted measurement
29716  * or undefined if the requested units are for a different
29717  * measurement type 
29718  */
29719 ilib.Measurement.FuelConsumption.prototype.convert = function(to) {
29720     if (!to || typeof(ilib.Measurement.FuelConsumption.ratios[this.normalizeUnits(to)]) === 'undefined') {
29721         return undefined;
29722     }
29723     return new ilib.Measurement({
29724         unit: to,
29725         amount: this
29726     });
29727 };
29728 /*["km/liter", "liter/100km", "mpg", "mpg(imp)"*/
29729 ilib.Measurement.FuelConsumption.aliases = {
29730     "Km/liter": "km/liter",
29731     "KM/Liter": "km/liter",
29732     "KM/L": "km/liter",
29733     "Kilometers Per Liter": "km/liter",
29734     "kilometers per liter": "km/liter",
29735     "km/l": "km/liter",
29736     "Kilometers/Liter": "km/liter",
29737     "Kilometer/Liter": "km/liter",
29738     "kilometers/liter": "km/liter",
29739     "kilometer/liter": "km/liter",
29740     "km/liter": "km/liter",
29741     "Liter/100km": "liter/100km",
29742     "Liters/100km": "liter/100km",
29743     "Liter/100kms": "liter/100km",
29744     "Liters/100kms": "liter/100km",
29745     "liter/100km": "liter/100km",
29746     "liters/100kms": "liter/100km",
29747     "liters/100km": "liter/100km",
29748     "liter/100kms": "liter/100km",
29749     "Liter/100KM": "liter/100km",
29750     "Liters/100KM": "liter/100km",
29751     "L/100km": "liter/100km",
29752     "L/100KM": "liter/100km",
29753     "l/100KM": "liter/100km",
29754     "l/100km": "liter/100km",
29755     "l/100kms": "liter/100km",
29756     "MPG(US)": "mpg",
29757     "USMPG ": "mpg",
29758     "mpg": "mpg",
29759     "mpgUS": "mpg",
29760     "mpg(US)": "mpg",
29761     "mpg(us)": "mpg",
29762     "mpg-us": "mpg",
29763     "mpg Imp": "mpg(imp)",
29764     "MPG(imp)": "mpg(imp)",
29765     "mpg(imp)": "mpg(imp)",
29766     "mpg-imp": "mpg(imp)"
29767 };
29768 
29769 ilib.Measurement.FuelConsumption.metricToUScustomary = {
29770     "km/liter": "mpg",
29771     "liter/100km": "mpg"
29772 };
29773 ilib.Measurement.FuelConsumption.metricToImperial = {
29774     "km/liter": "mpg(imp)",
29775     "liter/100km": "mpg(imp)"
29776 };
29777 
29778 ilib.Measurement.FuelConsumption.imperialToMetric = {
29779 	"mpg(imp)": "km/liter"
29780 };
29781 ilib.Measurement.FuelConsumption.imperialToUScustomary = {
29782 	"mpg(imp)": "mpg"
29783 };
29784 
29785 ilib.Measurement.FuelConsumption.uScustomaryToImperial = {
29786 	"mpg": "mpg(imp)"
29787 };
29788 ilib.Measurement.FuelConsumption.uScustomarylToMetric = {
29789 	"mpg": "km/liter"
29790 };
29791 
29792 /**
29793  * Localize the measurement to the commonly used measurement in that locale. For example
29794  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
29795  * the formatted number should be automatically converted to the most appropriate 
29796  * measure in the other system, in this case, mph. The formatted result should
29797  * appear as "37.3 mph". 
29798  * 
29799  * @abstract
29800  * @param {string} locale current locale string
29801  * @returns {ilib.Measurement} a new instance that is converted to locale
29802  */
29803 ilib.Measurement.FuelConsumption.prototype.localize = function(locale) {
29804 	var to;
29805 	if (locale === "en-US") {
29806 		to = ilib.Measurement.FuelConsumption.metricToUScustomary[this.unit] ||
29807 		    ilib.Measurement.FuelConsumption.imperialToUScustomary[this.unit] ||
29808 		    this.unit;
29809 	} else if (locale === "en-GB") {
29810 		to = ilib.Measurement.FuelConsumption.metricToImperial[this.unit] ||
29811 		    ilib.Measurement.FuelConsumption.uScustomaryToImperial[this.unit] ||
29812 		    this.unit;
29813 	} else {
29814 		to = ilib.Measurement.FuelConsumption.uScustomarylToMetric[this.unit] ||
29815 		    ilib.Measurement.FuelConsumption.imperialToUScustomary[this.unit] ||
29816 		    this.unit;
29817 	}
29818 	return new ilib.Measurement.FuelConsumption({
29819 	    unit: to,
29820 	    amount: this
29821 	});
29822 };
29823 
29824 /**
29825  * Convert a FuelConsumption to another measure.
29826  * 
29827  * @static
29828  * @param to {string} unit to convert to
29829  * @param from {string} unit to convert from
29830  * @param fuelConsumption {number} amount to be convert
29831  * @returns {number|undefined} the converted amount
29832  */
29833 ilib.Measurement.FuelConsumption.convert = function(to, from, fuelConsumption) {
29834     from = ilib.Measurement.FuelConsumption.aliases[from] || from;
29835     to = ilib.Measurement.FuelConsumption.aliases[to] || to;
29836     var returnValue = 0;
29837 
29838     switch (from) {
29839         case "km/liter":
29840             switch (to) {
29841                 case "km/liter":
29842                     returnValue = fuelConsumption * 1;
29843                     break;
29844                 case "liter/100km":
29845                     returnValue = 100 / fuelConsumption;
29846                     break;
29847                 case "mpg":
29848                     returnValue = fuelConsumption * 2.35215;
29849                     break;
29850                 case "mpg(imp)":
29851                     returnValue = fuelConsumption * 2.82481;
29852                     break;
29853             }
29854             break;
29855         case "liter/100km":
29856             switch (to) {
29857                 case "km/liter":
29858                     returnValue = 100 / fuelConsumption;
29859                     break;
29860                 case "liter/100km":
29861                     returnValue = fuelConsumption * 1;
29862                     break;
29863                 case "mpg":
29864                     returnValue = 235.215 / fuelConsumption;
29865                     break;
29866                 case "mpg(imp)":
29867                     returnValue = 282.481 / fuelConsumption;
29868                     break;
29869             }
29870             break;
29871         case "mpg":
29872             switch (to) {
29873                 case "km/liter":
29874                     returnValue = fuelConsumption * 0.425144;
29875                     break;
29876                 case "liter/100km":
29877                     returnValue = 235.215 / fuelConsumption;
29878                     break;
29879                 case "mpg":
29880                     returnValue = 1 * fuelConsumption;
29881                     break;
29882                 case "mpg(imp)":
29883                     returnValue = 1.20095 * fuelConsumption;
29884                     break;
29885             }
29886             break;
29887         case "mpg(imp)":
29888             switch (to) {
29889                 case "km/liter":
29890                     returnValue = fuelConsumption * 0.354006;
29891                     break;
29892                 case "liter/100km":
29893                     returnValue = 282.481 / fuelConsumption;
29894                     break;
29895                 case "mpg":
29896                     returnValue = 0.832674 * fuelConsumption;
29897                     break;
29898                 case "mpg(imp)":
29899                     returnValue = 1 * fuelConsumption;
29900                     break;
29901             }
29902             break;
29903     }
29904     return returnValue;
29905 };
29906 
29907 /**
29908  * Scale the measurement unit to an acceptable level. The scaling
29909  * happens so that the integer part of the amount is as small as
29910  * possible without being below zero. This will result in the 
29911  * largest units that can represent this measurement without
29912  * fractions. Measurements can only be scaled to other measurements 
29913  * of the same type.
29914  * 
29915  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
29916  * or undefined if the system can be inferred from the current measure
29917  * @return {ilib.Measurement} a new instance that is scaled to the 
29918  * right level
29919  */
29920 ilib.Measurement.FuelConsumption.prototype.scale = function(measurementsystem) {
29921     return new ilib.Measurement.FuelConsumption({
29922         unit: this.unit,
29923         amount: this.amount
29924     }); 
29925 };
29926 
29927 /**
29928  * @private
29929  * @static
29930  */
29931 ilib.Measurement.FuelConsumption.getMeasures = function() {
29932     var ret = [];
29933     ret.push("km/liter");
29934     ret.push("liter/100km");
29935     ret.push("mpg");
29936     ret.push("mpg(imp)");
29937     
29938     return ret;
29939 };
29940 
29941 //register with the factory method
29942 ilib.Measurement._constructors["fuelconsumption"] = ilib.Measurement.FuelConsumption;
29943 
29944 /*
29945  * volume.js - Unit conversions for volume
29946  * 
29947  * Copyright © 2014, JEDLSoft
29948  *
29949  * Licensed under the Apache License, Version 2.0 (the "License");
29950  * you may not use this file except in compliance with the License.
29951  * You may obtain a copy of the License at
29952  *
29953  *     http://www.apache.org/licenses/LICENSE-2.0
29954  *
29955  *
29956  * Unless required by applicable law or agreed to in writing, software
29957  * distributed under the License is distributed on an "AS IS" BASIS,
29958  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29959  *
29960  * See the License for the specific language governing permissions and
29961  * limitations under the License.
29962  */
29963 
29964 /*
29965 !depends 
29966 ilibglobal.js 
29967 unit.js
29968 */
29969 
29970 /**
29971  * @class
29972  * Create a new Volume measurement instance.
29973  * 
29974  * @constructor
29975  * @extends ilib.Measurement
29976  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
29977  * the construction of this instance
29978  */
29979 ilib.Measurement.Volume = function (options) {
29980 	this.unit = "cubic meter";
29981 	this.amount = 0;
29982 	this.aliases = ilib.Measurement.Volume.aliases; // share this table in all instances
29983 	
29984 	if (options) {
29985 		if (typeof(options.unit) !== 'undefined') {
29986 			this.originalUnit = options.unit;
29987 			this.unit = this.aliases[options.unit] || options.unit;
29988 		}
29989 		
29990 		if (typeof(options.amount) === 'object') {
29991 			if (options.amount.getMeasure() === "volume") {
29992 				this.amount = ilib.Measurement.Volume.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
29993 			} else {
29994 				throw "Cannot convert unit " + options.amount.unit + " to a volume";
29995 			}
29996 		} else if (typeof(options.amount) !== 'undefined') {
29997 			this.amount = parseFloat(options.amount);
29998 		}
29999 	}
30000 	
30001 	if (typeof(ilib.Measurement.Volume.ratios[this.unit]) === 'undefined') {
30002 		throw "Unknown unit: " + options.unit;
30003 	}
30004 };
30005 
30006 ilib.Measurement.Volume.ratios = {
30007     /*                 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, */
30008     "tsp" :            [1,    1,        0.333333,      0.300781,   0.166667, 0.0208333,  0.0104167,  0.00130208, 0.00130208,  0.000174063, 4.92892,    0.00492892, 4.9289e-6,   0.832674,      0.277558,      0.173474,        0.00867369,     0.00433684,     0.00108421          ],
30009     "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          ],
30010     "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          ],
30011     "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          ],
30012     "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           ],
30013     "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            ],
30014     "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            ],
30015     "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            ],
30016     "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             ],
30017     "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         ],
30018     "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            ],
30019     "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             ],
30020     "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          ],
30021     "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          ],
30022     "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             ],
30023     "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               ],
30024     "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                ],
30025     "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                   ]
30026 };
30027 
30028 ilib.Measurement.Volume.prototype = new ilib.Measurement({});
30029 ilib.Measurement.Volume.prototype.parent = ilib.Measurement;
30030 ilib.Measurement.Volume.prototype.constructor = ilib.Measurement.Volume;
30031 
30032 /**
30033  * Return the type of this measurement. Examples are "mass",
30034  * "length", "speed", etc. Measurements can only be converted
30035  * to measurements of the same type.<p>
30036  * 
30037  * The type of the units is determined automatically from the 
30038  * units. For example, the unit "grams" is type "mass". Use the 
30039  * static call {@link ilib.Measurement.getAvailableUnits}
30040  * to find out what units this version of ilib supports.
30041  *  
30042  * @return {string} the name of the type of this measurement
30043  */
30044 ilib.Measurement.Volume.prototype.getMeasure = function() {
30045 	return "volume";
30046 };
30047 
30048 /**
30049  * Return a new measurement instance that is converted to a new
30050  * measurement unit. Measurements can only be converted
30051  * to measurements of the same type.<p>
30052  *  
30053  * @param {string} to The name of the units to convert to
30054  * @return {ilib.Measurement|undefined} the converted measurement
30055  * or undefined if the requested units are for a different
30056  * measurement type 
30057  */
30058 ilib.Measurement.Volume.prototype.convert = function(to) {
30059 	if (!to || typeof(ilib.Measurement.Volume.ratios[this.normalizeUnits(to)]) === 'undefined') {
30060 		return undefined;
30061 	}
30062 	return new ilib.Measurement({
30063 		unit: to,
30064 		amount: this
30065 	});
30066 };
30067 
30068 ilib.Measurement.Volume.aliases = {
30069     "US gal": "gallon",
30070     "US gallon": "gallon",
30071     "US Gal": "gallon",
30072     "US Gallons": "gallon",
30073     "Gal(US)": "gallon",
30074     "gal(US)": "gallon",
30075     "gallon": "gallon",
30076     "quart": "quart",
30077     "US quart": "quart",
30078     "US quarts": "quart",
30079     "US Quart": "quart",
30080     "US Quarts": "quart",
30081     "US qt": "quart",
30082     "Qt(US)": "quart",
30083     "qt(US)": "quart",
30084     "US pint": "pint",
30085     "US Pint": "pint",
30086     "pint": "pint",
30087     "pint(US)": "pint",
30088     "Pint(US)": "pint",
30089     "US cup": "cup",
30090     "US Cup": "cup",
30091     "cup(US)": "cup",
30092     "Cup(US)": "cup",
30093     "cup": "cup",
30094     "us ounce": "us ounce",
30095     "US ounce": "us ounce",
30096     "℥": "us ounce",
30097     "US Oz": "us ounce",
30098     "oz(US)": "us ounce",
30099     "Oz(US)": "us ounce",
30100     "US tbsp": "tbsp",
30101     "tbsp": "tbsp",
30102     "tbsp(US)": "tbsp",
30103     "US tablespoon": "tbsp",
30104     "US tsp": "tsp",
30105     "tsp(US)": "tsp",
30106     "tsp": "tsp",
30107     "Cubic meter": "cubic meter",
30108     "cubic meter": "cubic meter",
30109     "Cubic metre": "cubic meter",
30110     "cubic metre": "cubic meter",
30111     "m3": "cubic meter",
30112     "Liter": "liter",
30113     "Liters": "liter",
30114     "liter": "liter",
30115     "L": "liter",
30116     "l": "liter",
30117     "Milliliter": "milliliter",
30118     "ML": "milliliter",
30119     "ml": "milliliter",
30120     "milliliter": "milliliter",
30121     "mL": "milliliter",
30122     "Imperial gal": "imperial gallon",
30123     "imperial gallon": "imperial gallon",
30124     "Imperial gallon": "imperial gallon",
30125     "gallon(imperial)": "imperial gallon",
30126     "gal(imperial)": "imperial gallon",
30127     "Imperial quart": "imperial quart",
30128     "imperial quart": "imperial quart",
30129     "Imperial Quart": "imperial quart",
30130     "IMperial qt": "imperial quart",
30131     "qt(Imperial)": "imperial quart",
30132     "quart(imperial)": "imperial quart",
30133     "Imperial pint": "imperial pint",
30134     "imperial pint": "imperial pint",
30135     "pint(Imperial)": "imperial pint",
30136     "imperial oz": "imperial ounce",
30137     "imperial ounce": "imperial ounce",
30138     "Imperial Ounce": "imperial ounce",
30139     "Imperial tbsp": "imperial tbsp",
30140     "imperial tbsp": "imperial tbsp",
30141     "tbsp(Imperial)": "imperial tbsp",
30142     "Imperial tsp": "imperial tsp",
30143     "imperial tsp": "imperial tsp",
30144     "tsp(Imperial)": "imperial tsp",
30145     "Cubic foot": "cubic foot",
30146     "cubic foot": "cubic foot",
30147     "Cubic Foot": "cubic foot",
30148     "Cubic feet": "cubic foot",
30149     "cubic Feet": "cubic foot",
30150     "cubic ft": "cubic foot",
30151     "ft3": "cubic foot",
30152     "Cubic inch": "cubic inch",
30153     "Cubic inches": "cubic inch",
30154     "cubic inches": "cubic inch",
30155     "cubic inch": "cubic inch",
30156     "cubic in": "cubic inch",
30157     "cu in": "cubic inch",
30158     "cu inch": "cubic inch",
30159     "inch³": "cubic inch",
30160     "in³": "cubic inch",
30161     "inch^3": "cubic inch",
30162     "in^3": "cubic inch",
30163     "c.i": "cubic inch",
30164     "CI": "cubic inch",
30165     "cui": "cubic inch"
30166 };
30167 
30168 /**
30169  * Convert a volume to another measure.
30170  * @static
30171  * @param to {string} unit to convert to
30172  * @param from {string} unit to convert from
30173  * @param volume {number} amount to be convert
30174  * @returns {number|undefined} the converted amount
30175  */
30176 ilib.Measurement.Volume.convert = function(to, from, volume) {
30177     from = ilib.Measurement.Volume.aliases[from] || from;
30178     to = ilib.Measurement.Volume.aliases[to] || to;
30179 	var fromRow = ilib.Measurement.Volume.ratios[from];
30180 	var toRow = ilib.Measurement.Volume.ratios[to];
30181 	if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
30182 		return undefined;
30183 	}	
30184 	var result = volume * fromRow[toRow[0]];
30185     return result;
30186 };
30187 
30188 /**
30189  * @private
30190  * @static
30191  */
30192 ilib.Measurement.Volume.getMeasures = function () {
30193 	var ret = [];
30194 	for (var m in ilib.Measurement.Volume.ratios) {
30195 		ret.push(m);
30196 	}
30197 	return ret;
30198 };
30199 ilib.Measurement.Volume.metricSystem = {
30200     "milliliter": 10,
30201     "liter": 11,
30202     "cubic meter": 12
30203 };
30204 ilib.Measurement.Volume.imperialSystem = {
30205     "imperial tsp": 13,
30206     "imperial tbsp": 14,
30207     "imperial ounce": 15,
30208     "imperial pint": 16,
30209     "imperial quart": 17,
30210     "imperial gallon": 18
30211 };
30212 ilib.Measurement.Volume.uscustomarySystem = {
30213     "tsp": 1,
30214     "tbsp": 2,
30215     "cubic inch": 3,
30216     "us ounce": 4,
30217     "cup": 5,
30218     "pint": 6,
30219     "quart": 7,
30220     "gallon": 8,
30221     "cubic foot": 9
30222 };
30223 
30224 ilib.Measurement.Volume.metricToUScustomary = {
30225     "milliliter": "tsp",
30226     "liter": "quart",
30227     "cubic meter": "cubic foot"
30228 };
30229 ilib.Measurement.Volume.metricToImperial = {
30230     "milliliter": "imperial tsp",
30231     "liter": "imperial quart",
30232     "cubic meter": "imperial gallon"
30233 };
30234 
30235 ilib.Measurement.Volume.imperialToMetric = {
30236     "imperial tsp": "milliliter",
30237     "imperial tbsp": "milliliter",
30238     "imperial ounce": "milliliter",
30239     "imperial pint": "liter",
30240     "imperial quart": "liter",
30241     "imperial gallon": "cubic meter"
30242 };
30243 ilib.Measurement.Volume.imperialToUScustomary = {
30244     "imperial tsp": "tsp",
30245     "imperial tbsp": "tbsp",
30246     "imperial ounce": "us ounce",
30247     "imperial pint": "pint",
30248     "imperial quart": "quart",
30249     "imperial gallon": "gallon"
30250 };
30251 
30252 ilib.Measurement.Volume.uScustomaryToImperial = {
30253     "tsp": "imperial tsp",
30254     "tbsp": "imperial tbsp",
30255     "cubic inch": "imperial tbsp",
30256     "us ounce": "imperial ounce",
30257     "cup": "imperial ounce",
30258     "pint": "imperial pint",
30259     "quart": "imperial quart",
30260     "gallon": "imperial gallon",
30261     "cubic foot": "imperial gallon"
30262 };
30263 ilib.Measurement.Volume.uScustomarylToMetric = {
30264     "tsp": "milliliter",
30265     "tbsp": "milliliter",
30266     "cubic inch": "milliliter",
30267     "us ounce": "milliliter",
30268     "cup": "milliliter",
30269     "pint": "liter",
30270     "quart": "liter",
30271     "gallon": "cubic meter",
30272     "cubic foot": "cubic meter"
30273 };
30274 
30275 /**
30276  * Localize the measurement to the commonly used measurement in that locale. For example
30277  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
30278  * the formatted number should be automatically converted to the most appropriate 
30279  * measure in the other system, in this case, mph. The formatted result should
30280  * appear as "37.3 mph". 
30281  * 
30282  * @abstract
30283  * @param {string} locale current locale string
30284  * @returns {ilib.Measurement} a new instance that is converted to locale
30285  */
30286 ilib.Measurement.Volume.prototype.localize = function(locale) {
30287 	var to;
30288 	if (locale === "en-US") {
30289 		to = ilib.Measurement.Volume.metricToUScustomary[this.unit] ||
30290 		    ilib.Measurement.Volume.imperialToUScustomary[this.unit] ||
30291 		    this.unit;
30292 	} else if (locale === "en-GB") {
30293 		to = ilib.Measurement.Volume.metricToImperial[this.unit] ||
30294 		    ilib.Measurement.Volume.uScustomaryToImperial[this.unit] ||
30295 		    this.unit;
30296 	} else {
30297 		to = ilib.Measurement.Volume.uScustomarylToMetric[this.unit] ||
30298 		    ilib.Measurement.Volume.imperialToUScustomary[this.unit] ||
30299 		    this.unit;
30300 	}
30301 	return new ilib.Measurement.Volume({
30302 	    unit: to,
30303 	    amount: this
30304 	});
30305 };
30306 
30307 /**
30308  * Scale the measurement unit to an acceptable level. The scaling
30309  * happens so that the integer part of the amount is as small as
30310  * possible without being below zero. This will result in the 
30311  * largest units that can represent this measurement without
30312  * fractions. Measurements can only be scaled to other measurements 
30313  * of the same type.
30314  * 
30315  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
30316  * or undefined if the system can be inferred from the current measure
30317  * @return {ilib.Measurement} a new instance that is scaled to the 
30318  * right level
30319  */
30320 ilib.Measurement.Volume.prototype.scale = function(measurementsystem) {
30321     var fromRow = ilib.Measurement.Volume.ratios[this.unit];
30322     var mSystem;
30323 
30324     if (measurementsystem === "metric"|| (typeof(measurementsystem) === 'undefined'
30325         && typeof(ilib.Measurement.Volume.metricSystem[this.unit]) !== 'undefined')) {
30326         mSystem = ilib.Measurement.Volume.metricSystem;
30327     } else if (measurementsystem === "uscustomary" || (typeof(measurementsystem) === 'undefined'
30328         && typeof(ilib.Measurement.Volume.uscustomarySystem[this.unit]) !== 'undefined')) {
30329         mSystem = ilib.Measurement.Volume.uscustomarySystem;
30330     } else if (measurementsystem === "imperial"|| (typeof(measurementsystem) === 'undefined'
30331         && typeof(ilib.Measurement.Volume.imperialSystem[this.unit]) !== 'undefined')) {
30332         mSystem = ilib.Measurement.Volume.imperialSystem;
30333     }
30334 
30335     var volume = this.amount;
30336     var munit = this.unit;
30337 
30338     for (var m in mSystem) {
30339         var tmp = this.amount * fromRow[mSystem[m]];
30340         if (tmp < 1) break;
30341         volume = tmp;
30342         munit = m;
30343     }
30344 
30345     return new ilib.Measurement.Volume({
30346         unit: munit,
30347         amount: volume
30348     });
30349 };
30350 
30351 
30352 
30353 //register with the factory method
30354 ilib.Measurement._constructors["volume"] = ilib.Measurement.Volume;
30355 
30356 
30357 /*
30358  * Energy.js - Unit conversions for Energys/energys
30359  *
30360  * Copyright © 2014, JEDLSoft
30361  *
30362  * Licensed under the Apache License, Version 2.0 (the "License");
30363  * you may not use this file except in compliance with the License.
30364  * You may obtain a copy of the License at
30365  *
30366  *     http://www.apache.org/licenses/LICENSE-2.0
30367  *
30368  * Unless required by applicable law or agreed to in writing, software
30369  * distributed under the License is distributed on an "AS IS" BASIS,
30370  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30371  *
30372  * See the License for the specific language governing permissions and
30373  * limitations under the License.
30374  */
30375 
30376 /*
30377 !depends
30378 ilibglobal.js
30379 */
30380 
30381 /**
30382  * @class
30383  * Create a new energy measurement instance.
30384  * 
30385  * @constructor
30386  * @extends ilib.Measurement
30387  * @param options {{unit:string,amount:number|string|undefined}} Options controlling
30388  * the construction of this instance
30389  */
30390 ilib.Measurement.Energy = function (options) {
30391 	this.unit = "ns";
30392 	this.amount = 0;
30393 	this.aliases = ilib.Measurement.Energy.aliases; // share this table in all instances
30394 
30395 	if (options) {
30396 		if (typeof(options.unit) !== 'undefined') {
30397 			this.originalUnit = options.unit;
30398 			this.unit = this.aliases[options.unit] || options.unit;
30399 		}
30400 
30401 		if (typeof(options.amount) === 'object') {
30402 			if (options.amount.getMeasure() === "energy") {
30403 				this.amount = ilib.Measurement.Energy.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
30404 			} else {
30405 				throw "Cannot convert units " + options.amount.unit + " to a energy";
30406 			}
30407 		} else if (typeof(options.amount) !== 'undefined') {
30408 			this.amount = parseFloat(options.amount);
30409 		}
30410 	}
30411 
30412 	if (typeof(ilib.Measurement.Energy.ratios[this.unit]) === 'undefined') {
30413 		throw "Unknown unit: " + options.unit;
30414 	}
30415 };
30416 
30417 ilib.Measurement.Energy.ratios = {
30418    /*                index mJ          J           BTU               kJ          Wh                Cal               MJ             kWh                gJ             MWh                 GWh         */
30419     "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  ],
30420     "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  ],
30421     "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  ],
30422     "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  ],
30423     "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            ],
30424     "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          ],
30425     "megajoule":    [ 7,   1e+9,       1e+6,       947.81707775,     1000,       277.77777778,     238.84589663,     1,             0.27777777778,     0.001,         2.7777777778e-4,    2.7777777778e-7   ],
30426     "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              ],
30427     "gigajoule":    [ 9,   1e+12,      1e+9,       947817.07775,     1e+6,       277777.77778,     238845.89663,     1000,          277.77777778,      1,             0.27777777778,      2.7777777778e-4   ],
30428     "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             ],
30429     "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                 ]
30430 };
30431 
30432 ilib.Measurement.Energy.prototype = new ilib.Measurement({});
30433 ilib.Measurement.Energy.prototype.parent = ilib.Measurement;
30434 ilib.Measurement.Energy.prototype.constructor = ilib.Measurement.Energy;
30435 
30436 /**
30437  * Return the type of this measurement. Examples are "mass",
30438  * "length", "speed", etc. Measurements can only be converted
30439  * to measurements of the same type.<p>
30440  * 
30441  * The type of the units is determined automatically from the 
30442  * units. For example, the unit "grams" is type "mass". Use the 
30443  * static call {@link ilib.Measurement.getAvailableUnits}
30444  * to find out what units this version of ilib supports.
30445  *  
30446  * @return {string} the name of the type of this measurement
30447  */
30448 ilib.Measurement.Energy.prototype.getMeasure = function() {
30449 	return "energy";
30450 };
30451 
30452 /**
30453  * Return a new measurement instance that is converted to a new
30454  * measurement unit. Measurements can only be converted
30455  * to measurements of the same type.<p>
30456  *  
30457  * @param {string} to The name of the units to convert to
30458  * @return {ilib.Measurement|undefined} the converted measurement
30459  * or undefined if the requested units are for a different
30460  * measurement type 
30461  */
30462 ilib.Measurement.Energy.prototype.convert = function(to) {
30463 	if (!to || typeof(ilib.Measurement.Energy.ratios[this.normalizeUnits(to)]) === 'undefined') {
30464 		return undefined;
30465 	}
30466 	return new ilib.Measurement({
30467 		unit: to,
30468 		amount: this
30469 	});
30470 };
30471 
30472 ilib.Measurement.Energy.aliases = {
30473     "milli joule": "millijoule",
30474     "millijoule": "millijoule",
30475     "MilliJoule": "millijoule",
30476     "milliJ": "millijoule",
30477     "joule": "joule",
30478     "J": "joule",
30479     "j": "joule",
30480     "Joule": "joule",
30481     "Joules": "joule",
30482     "joules": "joule",
30483     "BTU": "BTU",
30484     "btu": "BTU",
30485     "British thermal unit": "BTU",
30486     "british thermal unit": "BTU",
30487     "kilo joule": "kilojoule",
30488     "kJ": "kilojoule",
30489     "kj": "kilojoule",
30490     "Kj": "kilojoule",
30491     "kiloJoule": "kilojoule",
30492     "kilojoule": "kilojoule",
30493     "kjoule": "kilojoule",
30494     "watt hour": "watt hour",
30495     "Wh": "watt hour",
30496     "wh": "watt hour",
30497     "watt-hour": "watt hour",
30498     "calorie": "calorie",
30499     "Cal": "calorie",
30500     "cal": "calorie",
30501     "Calorie": "calorie",
30502     "calories": "calorie",
30503     "mega joule": "megajoule",
30504     "MJ": "megajoule",
30505     "megajoule": "megajoule",
30506     "megajoules": "megajoule",
30507     "Megajoules": "megajoule",
30508     "megaJoules": "megajoule",
30509     "MegaJoules": "megajoule",
30510     "megaJoule": "megajoule",
30511     "MegaJoule": "megajoule",
30512     "kilo Watt hour": "kilowatt hour",
30513     "kWh": "kilowatt hour",
30514     "kiloWh": "kilowatt hour",
30515     "KiloWh": "kilowatt hour",
30516     "KiloWatt-hour": "kilowatt hour",
30517     "kilowatt hour": "kilowatt hour",
30518     "kilowatt-hour": "kilowatt hour",
30519     "KiloWatt-hours": "kilowatt hour",
30520     "kilowatt-hours": "kilowatt hour",
30521     "Kilo Watt-hour": "kilowatt hour",
30522     "Kilo Watt-hours": "kilowatt hour",
30523     "giga joule": "gigajoule",
30524     "gJ": "gigajoule",
30525     "GJ": "gigajoule",
30526     "GigaJoule": "gigajoule",
30527     "gigaJoule": "gigajoule",
30528     "gigajoule": "gigajoule",   
30529     "GigaJoules": "gigajoule",
30530     "gigaJoules": "gigajoule",
30531     "Gigajoules": "gigajoule",
30532     "gigajoules": "gigajoule",
30533     "mega watt hour": "megawatt hour",
30534     "MWh": "megawatt hour",
30535     "MegaWh": "megawatt hour",
30536     "megaWh": "megawatt hour",
30537     "megaWatthour": "megawatt hour",
30538     "megaWatt-hour": "megawatt hour",
30539     "mega Watt-hour": "megawatt hour",
30540     "megaWatt hour": "megawatt hour",
30541     "megawatt hour": "megawatt hour",
30542     "mega Watt hour": "megawatt hour",
30543     "giga watt hour": "gigawatt hour",
30544     "gWh": "gigawatt hour",
30545     "GWh": "gigawatt hour",
30546     "gigaWh": "gigawatt hour",
30547     "gigaWatt-hour": "gigawatt hour",
30548     "gigawatt-hour": "gigawatt hour",
30549     "gigaWatt hour": "gigawatt hour",
30550     "gigawatt hour": "gigawatt hour",
30551     "gigawatthour": "gigawatt hour"
30552 };
30553 
30554 /**
30555  * Convert a energy to another measure.
30556  * @static
30557  * @param to {string} unit to convert to
30558  * @param from {string} unit to convert from
30559  * @param energy {number} amount to be convert
30560  * @returns {number|undefined} the converted amount
30561  */
30562 ilib.Measurement.Energy.convert = function(to, from, energy) {
30563     from = ilib.Measurement.Energy.aliases[from] || from;
30564     to = ilib.Measurement.Energy.aliases[to] || to;
30565     var fromRow = ilib.Measurement.Energy.ratios[from];
30566     var toRow = ilib.Measurement.Energy.ratios[to];
30567     if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
30568         return undefined;
30569     }
30570     return energy * fromRow[toRow[0]];
30571 };
30572 
30573 /**
30574  * @private
30575  * @static
30576  */
30577 ilib.Measurement.Energy.getMeasures = function () {
30578 	var ret = [];
30579 	for (var m in ilib.Measurement.Energy.ratios) {
30580 		ret.push(m);
30581 	}
30582 	return ret;
30583 };
30584 
30585 ilib.Measurement.Energy.metricJouleSystem = {
30586     "millijoule": 1,
30587     "joule": 2,
30588     "kilojoule": 4,
30589     "megajoule": 7,
30590     "gigajoule": 9
30591 };
30592 ilib.Measurement.Energy.metricWattHourSystem = {
30593     "watt hour": 5,
30594     "kilowatt hour": 8,
30595     "megawatt hour": 10,
30596     "gigawatt hour": 11
30597 };
30598 
30599 ilib.Measurement.Energy.imperialSystem = {
30600 	"BTU": 3
30601 };
30602 ilib.Measurement.Energy.uscustomarySystem = {
30603 	"calorie": 6
30604 };
30605 
30606 ilib.Measurement.Energy.metricToImperial = {
30607     "millijoule": "BTU",
30608     "joule": "BTU",
30609     "kilojoule": "BTU",
30610     "megajoule": "BTU",
30611     "gigajoule": "BTU"
30612 };
30613 ilib.Measurement.Energy.imperialToMetric = {
30614 	"BTU": "joule"
30615 };
30616 
30617 /**
30618  * Localize the measurement to the commonly used measurement in that locale. For example
30619  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
30620  * the formatted number should be automatically converted to the most appropriate 
30621  * measure in the other system, in this case, mph. The formatted result should
30622  * appear as "37.3 mph". 
30623  * 
30624  * @abstract
30625  * @param {string} locale current locale string
30626  * @returns {ilib.Measurement} a new instance that is converted to locale
30627  */
30628 ilib.Measurement.Energy.prototype.localize = function(locale) {
30629 	var to;
30630 	if (locale === "en-GB") {
30631 		to = ilib.Measurement.Energy.metricToImperial[this.unit] || this.unit;
30632 	} else {
30633 		to = ilib.Measurement.Energy.imperialToMetric[this.unit] || this.unit;
30634 	}
30635 
30636 	return new ilib.Measurement.Energy({
30637 	    unit: to,
30638 	    amount: this
30639 	});
30640 };
30641 
30642 /**
30643  * Scale the measurement unit to an acceptable level. The scaling
30644  * happens so that the integer part of the amount is as small as
30645  * possible without being below zero. This will result in the 
30646  * largest units that can represent this measurement without
30647  * fractions. Measurements can only be scaled to other measurements 
30648  * of the same type.
30649  * 
30650  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
30651  * or undefined if the system can be inferred from the current measure
30652  * @return {ilib.Measurement} a new instance that is scaled to the 
30653  * right level
30654  */
30655 ilib.Measurement.Energy.prototype.scale = function(measurementsystem) {
30656     var fromRow = ilib.Measurement.Energy.ratios[this.unit];
30657     var mSystem;
30658 
30659     if ((measurementsystem === "metric" && typeof(ilib.Measurement.Energy.metricJouleSystem[this.unit]) !== 'undefined')|| (typeof(measurementsystem) === 'undefined'
30660         && typeof(ilib.Measurement.Energy.metricJouleSystem[this.unit]) !== 'undefined')) {
30661         mSystem = ilib.Measurement.Energy.metricJouleSystem;
30662     }
30663     else if ((measurementsystem === "metric" && typeof(ilib.Measurement.Energy.metricWattHourSystem[this.unit]) !== 'undefined')|| (typeof(measurementsystem) === 'undefined'
30664         && typeof(ilib.Measurement.Energy.metricWattHourSystem[this.unit]) !== 'undefined')) {
30665         mSystem = ilib.Measurement.Energy.metricWattHourSystem;
30666     }
30667 
30668     else  if (measurementsystem === "uscustomary" || (typeof(measurementsystem) === 'undefined'
30669         && typeof(ilib.Measurement.Energy.uscustomarySystem[this.unit]) !== 'undefined')) {
30670         mSystem = ilib.Measurement.Energy.uscustomarySystem;
30671     }
30672     else if (measurementsystem === "imperial"|| (typeof(measurementsystem) === 'undefined'
30673         && typeof(ilib.Measurement.Energy.imperialSystem[this.unit]) !== 'undefined')) {
30674         mSystem = ilib.Measurement.Energy.imperialSystem;
30675     }
30676 
30677     var energy = this.amount;
30678     var munit = this.unit;
30679 
30680     for (var m in mSystem) {
30681         var tmp = this.amount * fromRow[mSystem[m]];
30682         if (tmp < 1) break;
30683         energy = tmp;
30684         munit = m;
30685     }
30686 
30687     return new ilib.Measurement.Energy({
30688         unit: munit,
30689         amount: energy
30690     });
30691 };
30692 //register with the factory method
30693 ilib.Measurement._constructors["energy"] = ilib.Measurement.Energy;
30694 
30695 /**
30696  * @license
30697  * Copyright © 2012-2013, JEDLSoft
30698  *
30699  * Licensed under the Apache License, Version 2.0 (the "License");
30700  * you may not use this file except in compliance with the License.
30701  * You may obtain a copy of the License at
30702  *
30703  *     http://www.apache.org/licenses/LICENSE-2.0
30704  *
30705  * Unless required by applicable law or agreed to in writing, software
30706  * distributed under the License is distributed on an "AS IS" BASIS,
30707  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30708  *
30709  * See the License for the specific language governing permissions and
30710  * limitations under the License.
30711  */
30712 
30713 /*
30714  * ilib-full-inc.js - metafile that includes all other js files
30715  */
30716 
30717 /* !depends
30718 ilibglobal.js
30719 daterangefmt.js
30720 date.js
30721 calendar/hebrewdate.js
30722 calendar/hebrew.js
30723 calendar/islamic.js
30724 calendar/islamicdate.js
30725 calendar/julian.js
30726 calendar/juliandate.js
30727 calendar/gregorian.js
30728 calendar/gregoriandate.js
30729 calendar/thaisolar.js
30730 calendar/thaisolardate.js
30731 calendar/persian.js
30732 calendar/persiandate.js
30733 calendar/persianastro.js
30734 calendar/persianastrodate.js
30735 calendar/han.js
30736 calendar/handate.js
30737 calendar/ethiopic.js
30738 calendar/ethiopicdate.js
30739 calendar/coptic.js
30740 calendar/copticdate.js
30741 numprs.js
30742 numfmt.js
30743 julianday.js
30744 datefmt.js
30745 calendar.js
30746 util/utils.js
30747 locale.js
30748 strings.js
30749 durfmt.js
30750 resources.js
30751 ctype.js
30752 localeinfo.js
30753 daterangefmt.js
30754 ctype.isalnum.js
30755 ctype.isalpha.js
30756 ctype.isascii.js
30757 ctype.isblank.js
30758 ctype.iscntrl.js
30759 ctype.isdigit.js
30760 ctype.isgraph.js
30761 ctype.isideo.js
30762 ctype.islower.js
30763 ctype.isprint.js
30764 ctype.ispunct.js
30765 ctype.isspace.js
30766 ctype.isupper.js
30767 ctype.isxdigit.js
30768 ctype.isscript.js
30769 scriptinfo.js
30770 nameprs.js
30771 namefmt.js
30772 addressprs.js
30773 addressfmt.js
30774 collate.js
30775 nfkc/all.js
30776 localematch.js
30777 normstring.js
30778 maps/casemapper.js
30779 glyphstring.js
30780 phone/phonefmt.js
30781 phone/phonegeo.js
30782 phone/phonenum.js
30783 unit.js
30784 unitfmt.js
30785 units/length.js
30786 units/speed.js
30787 units/digitalStorage.js
30788 units/temperature.js
30789 units/unknown.js
30790 units/time.js
30791 units/mass.js
30792 units/area.js
30793 units/fuelConsumption.js
30794 units/volume.js	
30795 units/energy.js
30796 */
30797 
30798