web/data/cubicweb.timeline-bundle.js
branch894685124c68
changeset 1200 0d12d4371d11
parent 1156 4b920f836567
child 2097 400bdbcc5699
equal deleted inserted replaced
1199:7fa66717175b 1200:0d12d4371d11
     1 
     1 var SimileAjax_urlPrefix = baseuri() + 'data/';
     2 var SimileAjax = {
     2 var Timeline_urlPrefix = baseuri() + 'data/';
     3     loaded:                 false,
     3 
     4     loadingScriptsCount:    0,
     4 /*==================================================
     5     error:                  null,
     5  *  Simile Ajax API
     6     params:                 { bundle:"true" }
     6  *
     7 };
     7  *  Include this file in your HTML file as follows:
     8 
     8  *
     9 
     9  *    <script src="http://simile.mit.edu/ajax/api/simile-ajax-api.js" type="text/javascript"></script>
       
    10  *
       
    11  *==================================================
       
    12  */
       
    13 
       
    14 if (typeof SimileAjax == "undefined") {
       
    15     var SimileAjax = {
       
    16         loaded:                 false,
       
    17         loadingScriptsCount:    0,
       
    18         error:                  null,
       
    19         params:                 { bundle:"true" }
       
    20     };
       
    21 
       
    22     SimileAjax.Platform = new Object();
       
    23         /*
       
    24             HACK: We need these 2 things here because we cannot simply append
       
    25             a <script> element containing code that accesses SimileAjax.Platform
       
    26             to initialize it because IE executes that <script> code first
       
    27             before it loads ajax.js and platform.js.
       
    28         */
       
    29 
       
    30     var getHead = function(doc) {
       
    31         return doc.getElementsByTagName("head")[0];
       
    32     };
       
    33 
       
    34     SimileAjax.findScript = function(doc, substring) {
       
    35         var heads = doc.documentElement.getElementsByTagName("head");
       
    36         for (var h = 0; h < heads.length; h++) {
       
    37             var node = heads[h].firstChild;
       
    38             while (node != null) {
       
    39                 if (node.nodeType == 1 && node.tagName.toLowerCase() == "script") {
       
    40                     var url = node.src;
       
    41                     var i = url.indexOf(substring);
       
    42                     if (i >= 0) {
       
    43                         return url;
       
    44                     }
       
    45                 }
       
    46                 node = node.nextSibling;
       
    47             }
       
    48         }
       
    49         return null;
       
    50     };
       
    51     SimileAjax.includeJavascriptFile = function(doc, url, onerror, charset) {
       
    52         onerror = onerror || "";
       
    53         if (doc.body == null) {
       
    54             try {
       
    55                 var q = "'" + onerror.replace( /'/g, '&apos' ) + "'"; // "
       
    56                 doc.write("<script src='" + url + "' onerror="+ q +
       
    57                           (charset ? " charset='"+ charset +"'" : "") +
       
    58                           " type='text/javascript'>"+ onerror + "</script>");
       
    59                 return;
       
    60             } catch (e) {
       
    61                 // fall through
       
    62             }
       
    63         }
       
    64 
       
    65         var script = doc.createElement("script");
       
    66         if (onerror) {
       
    67             try { script.innerHTML = onerror; } catch(e) {}
       
    68             script.setAttribute("onerror", onerror);
       
    69         }
       
    70         if (charset) {
       
    71             script.setAttribute("charset", charset);
       
    72         }
       
    73         script.type = "text/javascript";
       
    74         script.language = "JavaScript";
       
    75         script.src = url;
       
    76         return getHead(doc).appendChild(script);
       
    77     };
       
    78     SimileAjax.includeJavascriptFiles = function(doc, urlPrefix, filenames) {
       
    79         for (var i = 0; i < filenames.length; i++) {
       
    80             SimileAjax.includeJavascriptFile(doc, urlPrefix + filenames[i]);
       
    81         }
       
    82         SimileAjax.loadingScriptsCount += filenames.length;
       
    83         SimileAjax.includeJavascriptFile(doc, SimileAjax.urlPrefix + "scripts/signal.js?" + filenames.length);
       
    84     };
       
    85     SimileAjax.includeCssFile = function(doc, url) {
       
    86         if (doc.body == null) {
       
    87             try {
       
    88                 doc.write("<link rel='stylesheet' href='" + url + "' type='text/css'/>");
       
    89                 return;
       
    90             } catch (e) {
       
    91                 // fall through
       
    92             }
       
    93         }
       
    94 
       
    95         var link = doc.createElement("link");
       
    96         link.setAttribute("rel", "stylesheet");
       
    97         link.setAttribute("type", "text/css");
       
    98         link.setAttribute("href", url);
       
    99         getHead(doc).appendChild(link);
       
   100     };
       
   101     SimileAjax.includeCssFiles = function(doc, urlPrefix, filenames) {
       
   102         for (var i = 0; i < filenames.length; i++) {
       
   103             SimileAjax.includeCssFile(doc, urlPrefix + filenames[i]);
       
   104         }
       
   105     };
       
   106 
       
   107     /**
       
   108      * Append into urls each string in suffixes after prefixing it with urlPrefix.
       
   109      * @param {Array} urls
       
   110      * @param {String} urlPrefix
       
   111      * @param {Array} suffixes
       
   112      */
       
   113     SimileAjax.prefixURLs = function(urls, urlPrefix, suffixes) {
       
   114         for (var i = 0; i < suffixes.length; i++) {
       
   115             urls.push(urlPrefix + suffixes[i]);
       
   116         }
       
   117     };
       
   118 
       
   119     /**
       
   120      * Parse out the query parameters from a URL
       
   121      * @param {String} url    the url to parse, or location.href if undefined
       
   122      * @param {Object} to     optional object to extend with the parameters
       
   123      * @param {Object} types  optional object mapping keys to value types
       
   124      *        (String, Number, Boolean or Array, String by default)
       
   125      * @return a key/value Object whose keys are the query parameter names
       
   126      * @type Object
       
   127      */
       
   128     SimileAjax.parseURLParameters = function(url, to, types) {
       
   129         to = to || {};
       
   130         types = types || {};
       
   131 
       
   132         if (typeof url == "undefined") {
       
   133             url = location.href;
       
   134         }
       
   135         var q = url.indexOf("?");
       
   136         if (q < 0) {
       
   137             return to;
       
   138         }
       
   139         url = (url+"#").slice(q+1, url.indexOf("#")); // toss the URL fragment
       
   140 
       
   141         var params = url.split("&"), param, parsed = {};
       
   142         var decode = window.decodeURIComponent || unescape;
       
   143         for (var i = 0; param = params[i]; i++) {
       
   144             var eq = param.indexOf("=");
       
   145             var name = decode(param.slice(0,eq));
       
   146             var old = parsed[name];
       
   147             if (typeof old == "undefined") {
       
   148                 old = [];
       
   149             } else if (!(old instanceof Array)) {
       
   150                 old = [old];
       
   151             }
       
   152             parsed[name] = old.concat(decode(param.slice(eq+1)));
       
   153         }
       
   154         for (var i in parsed) {
       
   155             if (!parsed.hasOwnProperty(i)) continue;
       
   156             var type = types[i] || String;
       
   157             var data = parsed[i];
       
   158             if (!(data instanceof Array)) {
       
   159                 data = [data];
       
   160             }
       
   161             if (type === Boolean && data[0] == "false") {
       
   162                 to[i] = false; // because Boolean("false") === true
       
   163             } else {
       
   164                 to[i] = type.apply(this, data);
       
   165             }
       
   166         }
       
   167         return to;
       
   168     };
       
   169 
       
   170     (function() {
       
   171         var javascriptFiles = [
       
   172             "jquery-1.2.6.js",
       
   173             "platform.js",
       
   174             "debug.js",
       
   175             "xmlhttp.js",
       
   176             "json.js",
       
   177             "dom.js",
       
   178             "graphics.js",
       
   179             "date-time.js",
       
   180             "string.js",
       
   181             "html.js",
       
   182             "data-structure.js",
       
   183             "units.js",
       
   184 
       
   185             "ajax.js",
       
   186             "history.js",
       
   187             "window-manager.js"
       
   188         ];
       
   189         var cssFiles = [
       
   190             "graphics.css"
       
   191         ];
       
   192 
       
   193         if (typeof SimileAjax_urlPrefix == "string") {
       
   194             SimileAjax.urlPrefix = SimileAjax_urlPrefix;
       
   195         } else {
       
   196             var url = SimileAjax.findScript(document, "simile-ajax-api.js");
       
   197             if (url == null) {
       
   198                 SimileAjax.error = new Error("Failed to derive URL prefix for Simile Ajax API code files");
       
   199                 return;
       
   200             }
       
   201 
       
   202             SimileAjax.urlPrefix = url.substr(0, url.indexOf("simile-ajax-api.js"));
       
   203         }
       
   204 
       
   205         SimileAjax.parseURLParameters(url, SimileAjax.params, {bundle:Boolean});
       
   206 //         if (SimileAjax.params.bundle) {
       
   207 //             SimileAjax.includeJavascriptFiles(document, SimileAjax.urlPrefix, [ "simile-ajax-bundle.js" ]);
       
   208 //         } else {
       
   209 //             SimileAjax.includeJavascriptFiles(document, SimileAjax.urlPrefix + "scripts/", javascriptFiles);
       
   210 //         }
       
   211         SimileAjax.includeCssFiles(document, SimileAjax.urlPrefix + "styles/", cssFiles);
       
   212 
       
   213         SimileAjax.loaded = true;
       
   214     })();
       
   215 }
       
   216 /*==================================================
       
   217  *  Platform Utility Functions and Constants
       
   218  *==================================================
       
   219  */
       
   220 
       
   221 /*  This must be called after our jQuery has been loaded
       
   222     but before control returns to user-code.
       
   223 */
       
   224 SimileAjax.jQuery = jQuery;
       
   225 // SimileAjax.jQuery = jQuery.noConflict(true);
       
   226 if (typeof window["$"] == "undefined") {
       
   227     window.$ = SimileAjax.jQuery;
       
   228 }
       
   229 
       
   230 SimileAjax.Platform.os = {
       
   231     isMac:   false,
       
   232     isWin:   false,
       
   233     isWin32: false,
       
   234     isUnix:  false
       
   235 };
       
   236 SimileAjax.Platform.browser = {
       
   237     isIE:           false,
       
   238     isNetscape:     false,
       
   239     isMozilla:      false,
       
   240     isFirefox:      false,
       
   241     isOpera:        false,
       
   242     isSafari:       false,
       
   243 
       
   244     majorVersion:   0,
       
   245     minorVersion:   0
       
   246 };
       
   247 
       
   248 (function() {
       
   249     var an = navigator.appName.toLowerCase();
       
   250 	var ua = navigator.userAgent.toLowerCase();
       
   251 
       
   252     /*
       
   253      *  Operating system
       
   254      */
       
   255 	SimileAjax.Platform.os.isMac = (ua.indexOf('mac') != -1);
       
   256 	SimileAjax.Platform.os.isWin = (ua.indexOf('win') != -1);
       
   257 	SimileAjax.Platform.os.isWin32 = SimileAjax.Platform.isWin && (
       
   258         ua.indexOf('95') != -1 ||
       
   259         ua.indexOf('98') != -1 ||
       
   260         ua.indexOf('nt') != -1 ||
       
   261         ua.indexOf('win32') != -1 ||
       
   262         ua.indexOf('32bit') != -1
       
   263     );
       
   264 	SimileAjax.Platform.os.isUnix = (ua.indexOf('x11') != -1);
       
   265 
       
   266     /*
       
   267      *  Browser
       
   268      */
       
   269     SimileAjax.Platform.browser.isIE = (an.indexOf("microsoft") != -1);
       
   270     SimileAjax.Platform.browser.isNetscape = (an.indexOf("netscape") != -1);
       
   271     SimileAjax.Platform.browser.isMozilla = (ua.indexOf("mozilla") != -1);
       
   272     SimileAjax.Platform.browser.isFirefox = (ua.indexOf("firefox") != -1);
       
   273     SimileAjax.Platform.browser.isOpera = (an.indexOf("opera") != -1);
       
   274     SimileAjax.Platform.browser.isSafari = (an.indexOf("safari") != -1);
       
   275 
       
   276     var parseVersionString = function(s) {
       
   277         var a = s.split(".");
       
   278         SimileAjax.Platform.browser.majorVersion = parseInt(a[0]);
       
   279         SimileAjax.Platform.browser.minorVersion = parseInt(a[1]);
       
   280     };
       
   281     var indexOf = function(s, sub, start) {
       
   282         var i = s.indexOf(sub, start);
       
   283         return i >= 0 ? i : s.length;
       
   284     };
       
   285 
       
   286     if (SimileAjax.Platform.browser.isMozilla) {
       
   287         var offset = ua.indexOf("mozilla/");
       
   288         if (offset >= 0) {
       
   289             parseVersionString(ua.substring(offset + 8, indexOf(ua, " ", offset)));
       
   290         }
       
   291     }
       
   292     if (SimileAjax.Platform.browser.isIE) {
       
   293         var offset = ua.indexOf("msie ");
       
   294         if (offset >= 0) {
       
   295             parseVersionString(ua.substring(offset + 5, indexOf(ua, ";", offset)));
       
   296         }
       
   297     }
       
   298     if (SimileAjax.Platform.browser.isNetscape) {
       
   299         var offset = ua.indexOf("rv:");
       
   300         if (offset >= 0) {
       
   301             parseVersionString(ua.substring(offset + 3, indexOf(ua, ")", offset)));
       
   302         }
       
   303     }
       
   304     if (SimileAjax.Platform.browser.isFirefox) {
       
   305         var offset = ua.indexOf("firefox/");
       
   306         if (offset >= 0) {
       
   307             parseVersionString(ua.substring(offset + 8, indexOf(ua, " ", offset)));
       
   308         }
       
   309     }
       
   310 
       
   311     if (!("localeCompare" in String.prototype)) {
       
   312         String.prototype.localeCompare = function (s) {
       
   313             if (this < s) return -1;
       
   314             else if (this > s) return 1;
       
   315             else return 0;
       
   316         };
       
   317     }
       
   318 })();
       
   319 
       
   320 SimileAjax.Platform.getDefaultLocale = function() {
       
   321     return SimileAjax.Platform.clientLocale;
       
   322 };/*==================================================
       
   323  *  Debug Utility Functions
       
   324  *==================================================
       
   325  */
       
   326 
       
   327 SimileAjax.Debug = {
       
   328     silent: false
       
   329 };
       
   330 
       
   331 SimileAjax.Debug.log = function(msg) {
       
   332     var f;
       
   333     if ("console" in window && "log" in window.console) { // FireBug installed
       
   334         f = function(msg2) {
       
   335             console.log(msg2);
       
   336         }
       
   337     } else {
       
   338         f = function(msg2) {
       
   339             if (!SimileAjax.Debug.silent) {
       
   340                 alert(msg2);
       
   341             }
       
   342         }
       
   343     }
       
   344     SimileAjax.Debug.log = f;
       
   345     f(msg);
       
   346 };
       
   347 
       
   348 SimileAjax.Debug.warn = function(msg) {
       
   349     var f;
       
   350     if ("console" in window && "warn" in window.console) { // FireBug installed
       
   351         f = function(msg2) {
       
   352             console.warn(msg2);
       
   353         }
       
   354     } else {
       
   355         f = function(msg2) {
       
   356             if (!SimileAjax.Debug.silent) {
       
   357                 alert(msg2);
       
   358             }
       
   359         }
       
   360     }
       
   361     SimileAjax.Debug.warn = f;
       
   362     f(msg);
       
   363 };
       
   364 
       
   365 SimileAjax.Debug.exception = function(e, msg) {
       
   366     var f, params = SimileAjax.parseURLParameters();
       
   367     if (params.errors == "throw" || SimileAjax.params.errors == "throw") {
       
   368         f = function(e2, msg2) {
       
   369             throw(e2); // do not hide from browser's native debugging features
       
   370         };
       
   371     } else if ("console" in window && "error" in window.console) { // FireBug installed
       
   372         f = function(e2, msg2) {
       
   373             if (msg2 != null) {
       
   374                 console.error(msg2 + " %o", e2);
       
   375             } else {
       
   376                 console.error(e2);
       
   377             }
       
   378             throw(e2); // do not hide from browser's native debugging features
       
   379         };
       
   380     } else {
       
   381         f = function(e2, msg2) {
       
   382             if (!SimileAjax.Debug.silent) {
       
   383                 alert("Caught exception: " + msg2 + "\n\nDetails: " + ("description" in e2 ? e2.description : e2));
       
   384             }
       
   385             throw(e2); // do not hide from browser's native debugging features
       
   386         };
       
   387     }
       
   388     SimileAjax.Debug.exception = f;
       
   389     f(e, msg);
       
   390 };
       
   391 
       
   392 SimileAjax.Debug.objectToString = function(o) {
       
   393     return SimileAjax.Debug._objectToString(o, "");
       
   394 };
       
   395 
       
   396 SimileAjax.Debug._objectToString = function(o, indent) {
       
   397     var indent2 = indent + " ";
       
   398     if (typeof o == "object") {
       
   399         var s = "{";
       
   400         for (n in o) {
       
   401             s += indent2 + n + ": " + SimileAjax.Debug._objectToString(o[n], indent2) + "\n";
       
   402         }
       
   403         s += indent + "}";
       
   404         return s;
       
   405     } else if (typeof o == "array") {
       
   406         var s = "[";
       
   407         for (var n = 0; n < o.length; n++) {
       
   408             s += SimileAjax.Debug._objectToString(o[n], indent2) + "\n";
       
   409         }
       
   410         s += indent + "]";
       
   411         return s;
       
   412     } else {
       
   413         return o;
       
   414     }
       
   415 };
    10 /**
   416 /**
    11  * Parse out the query parameters from a URL
   417  * @fileOverview XmlHttp utility functions
    12  * @param {String} url    the url to parse, or location.href if undefined
   418  * @name SimileAjax.XmlHttp
    13  * @param {Object} to     optional object to extend with the parameters
       
    14  * @param {Object} types  optional object mapping keys to value types
       
    15  *        (String, Number, Boolean or Array, String by default)
       
    16  * @return a key/value Object whose keys are the query parameter names
       
    17  * @type Object
       
    18  */
   419  */
    19 SimileAjax.parseURLParameters = function(url, to, types) {
   420 
    20     to = to || {};
   421 SimileAjax.XmlHttp = new Object();
    21     types = types || {};
   422 
    22 
   423 /**
    23     if (typeof url == "undefined") {
   424  *  Callback for XMLHttp onRequestStateChange.
    24         url = location.href;
   425  */
    25     }
   426 SimileAjax.XmlHttp._onReadyStateChange = function(xmlhttp, fError, fDone) {
    26     var q = url.indexOf("?");
   427     switch (xmlhttp.readyState) {
    27     if (q < 0) {
   428     // 1: Request not yet made
    28         return to;
   429     // 2: Contact established with server but nothing downloaded yet
    29     }
   430     // 3: Called multiple while downloading in progress
    30     url = (url+"#").slice(q+1, url.indexOf("#")); // toss the URL fragment
   431 
    31 
   432     // Download complete
    32     var params = url.split("&"), param, parsed = {};
   433     case 4:
    33     var decode = window.decodeURIComponent || unescape;
   434         try {
    34     for (var i = 0; param = params[i]; i++) {
   435             if (xmlhttp.status == 0     // file:// urls, works on Firefox
    35         var eq = param.indexOf("=");
   436              || xmlhttp.status == 200   // http:// urls
    36         var name = decode(param.slice(0,eq));
   437             ) {
    37         var old = parsed[name];
   438                 if (fDone) {
    38         if (typeof old == "undefined") {
   439                     fDone(xmlhttp);
    39             old = [];
   440                 }
    40         } else if (!(old instanceof Array)) {
   441             } else {
    41             old = [old];
   442                 if (fError) {
    42         }
   443                     fError(
    43         parsed[name] = old.concat(decode(param.slice(eq+1)));
   444                         xmlhttp.statusText,
    44     }
   445                         xmlhttp.status,
    45     for (var i in parsed) {
   446                         xmlhttp
    46         if (!parsed.hasOwnProperty(i)) continue;
   447                     );
    47         var type = types[i] || String;
   448                 }
    48         var data = parsed[i];
   449             }
    49         if (!(data instanceof Array)) {
   450         } catch (e) {
    50             data = [data];
   451             SimileAjax.Debug.exception("XmlHttp: Error handling onReadyStateChange", e);
    51         }
   452         }
    52         if (type === Boolean && data[0] == "false") {
   453         break;
    53             to[i] = false; // because Boolean("false") === true
   454     }
       
   455 };
       
   456 
       
   457 /**
       
   458  *  Creates an XMLHttpRequest object. On the first run, this
       
   459  *  function creates a platform-specific function for
       
   460  *  instantiating an XMLHttpRequest object and then replaces
       
   461  *  itself with that function.
       
   462  */
       
   463 SimileAjax.XmlHttp._createRequest = function() {
       
   464     if (SimileAjax.Platform.browser.isIE) {
       
   465         var programIDs = [
       
   466         "Msxml2.XMLHTTP",
       
   467         "Microsoft.XMLHTTP",
       
   468         "Msxml2.XMLHTTP.4.0"
       
   469         ];
       
   470         for (var i = 0; i < programIDs.length; i++) {
       
   471             try {
       
   472                 var programID = programIDs[i];
       
   473                 var f = function() {
       
   474                     return new ActiveXObject(programID);
       
   475                 };
       
   476                 var o = f();
       
   477 
       
   478                 // We are replacing the SimileAjax._createXmlHttpRequest
       
   479                 // function with this inner function as we've
       
   480                 // found out that it works. This is so that we
       
   481                 // don't have to do all the testing over again
       
   482                 // on subsequent calls.
       
   483                 SimileAjax.XmlHttp._createRequest = f;
       
   484 
       
   485                 return o;
       
   486             } catch (e) {
       
   487                 // silent
       
   488             }
       
   489         }
       
   490         // fall through to try new XMLHttpRequest();
       
   491     }
       
   492 
       
   493     try {
       
   494         var f = function() {
       
   495             return new XMLHttpRequest();
       
   496         };
       
   497         var o = f();
       
   498 
       
   499         // We are replacing the SimileAjax._createXmlHttpRequest
       
   500         // function with this inner function as we've
       
   501         // found out that it works. This is so that we
       
   502         // don't have to do all the testing over again
       
   503         // on subsequent calls.
       
   504         SimileAjax.XmlHttp._createRequest = f;
       
   505 
       
   506         return o;
       
   507     } catch (e) {
       
   508         throw new Error("Failed to create an XMLHttpRequest object");
       
   509     }
       
   510 };
       
   511 
       
   512 /**
       
   513  * Performs an asynchronous HTTP GET.
       
   514  *
       
   515  * @param {Function} fError a function of the form
       
   516      function(statusText, statusCode, xmlhttp)
       
   517  * @param {Function} fDone a function of the form function(xmlhttp)
       
   518  */
       
   519 SimileAjax.XmlHttp.get = function(url, fError, fDone) {
       
   520     var xmlhttp = SimileAjax.XmlHttp._createRequest();
       
   521 
       
   522     xmlhttp.open("GET", url, true);
       
   523     xmlhttp.onreadystatechange = function() {
       
   524         SimileAjax.XmlHttp._onReadyStateChange(xmlhttp, fError, fDone);
       
   525     };
       
   526     xmlhttp.send(null);
       
   527 };
       
   528 
       
   529 /**
       
   530  * Performs an asynchronous HTTP POST.
       
   531  *
       
   532  * @param {Function} fError a function of the form
       
   533      function(statusText, statusCode, xmlhttp)
       
   534  * @param {Function} fDone a function of the form function(xmlhttp)
       
   535  */
       
   536 SimileAjax.XmlHttp.post = function(url, body, fError, fDone) {
       
   537     var xmlhttp = SimileAjax.XmlHttp._createRequest();
       
   538 
       
   539     xmlhttp.open("POST", url, true);
       
   540     xmlhttp.onreadystatechange = function() {
       
   541         SimileAjax.XmlHttp._onReadyStateChange(xmlhttp, fError, fDone);
       
   542     };
       
   543     xmlhttp.send(body);
       
   544 };
       
   545 
       
   546 SimileAjax.XmlHttp._forceXML = function(xmlhttp) {
       
   547     try {
       
   548         xmlhttp.overrideMimeType("text/xml");
       
   549     } catch (e) {
       
   550         xmlhttp.setrequestheader("Content-Type", "text/xml");
       
   551     }
       
   552 };/*
       
   553  *  Copied directly from http://www.json.org/json.js.
       
   554  */
       
   555 
       
   556 /*
       
   557     json.js
       
   558     2006-04-28
       
   559 
       
   560     This file adds these methods to JavaScript:
       
   561 
       
   562         object.toJSONString()
       
   563 
       
   564             This method produces a JSON text from an object. The
       
   565             object must not contain any cyclical references.
       
   566 
       
   567         array.toJSONString()
       
   568 
       
   569             This method produces a JSON text from an array. The
       
   570             array must not contain any cyclical references.
       
   571 
       
   572         string.parseJSON()
       
   573 
       
   574             This method parses a JSON text to produce an object or
       
   575             array. It will return false if there is an error.
       
   576 */
       
   577 
       
   578 SimileAjax.JSON = new Object();
       
   579 
       
   580 (function () {
       
   581     var m = {
       
   582         '\b': '\\b',
       
   583         '\t': '\\t',
       
   584         '\n': '\\n',
       
   585         '\f': '\\f',
       
   586         '\r': '\\r',
       
   587         '"' : '\\"',
       
   588         '\\': '\\\\'
       
   589     };
       
   590     var s = {
       
   591         array: function (x) {
       
   592             var a = ['['], b, f, i, l = x.length, v;
       
   593             for (i = 0; i < l; i += 1) {
       
   594                 v = x[i];
       
   595                 f = s[typeof v];
       
   596                 if (f) {
       
   597                     v = f(v);
       
   598                     if (typeof v == 'string') {
       
   599                         if (b) {
       
   600                             a[a.length] = ',';
       
   601                         }
       
   602                         a[a.length] = v;
       
   603                         b = true;
       
   604                     }
       
   605                 }
       
   606             }
       
   607             a[a.length] = ']';
       
   608             return a.join('');
       
   609         },
       
   610         'boolean': function (x) {
       
   611             return String(x);
       
   612         },
       
   613         'null': function (x) {
       
   614             return "null";
       
   615         },
       
   616         number: function (x) {
       
   617             return isFinite(x) ? String(x) : 'null';
       
   618         },
       
   619         object: function (x) {
       
   620             if (x) {
       
   621                 if (x instanceof Array) {
       
   622                     return s.array(x);
       
   623                 }
       
   624                 var a = ['{'], b, f, i, v;
       
   625                 for (i in x) {
       
   626                     v = x[i];
       
   627                     f = s[typeof v];
       
   628                     if (f) {
       
   629                         v = f(v);
       
   630                         if (typeof v == 'string') {
       
   631                             if (b) {
       
   632                                 a[a.length] = ',';
       
   633                             }
       
   634                             a.push(s.string(i), ':', v);
       
   635                             b = true;
       
   636                         }
       
   637                     }
       
   638                 }
       
   639                 a[a.length] = '}';
       
   640                 return a.join('');
       
   641             }
       
   642             return 'null';
       
   643         },
       
   644         string: function (x) {
       
   645             if (/["\\\x00-\x1f]/.test(x)) {
       
   646                 x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
       
   647                     var c = m[b];
       
   648                     if (c) {
       
   649                         return c;
       
   650                     }
       
   651                     c = b.charCodeAt();
       
   652                     return '\\u00' +
       
   653                         Math.floor(c / 16).toString(16) +
       
   654                         (c % 16).toString(16);
       
   655                 });
       
   656             }
       
   657             return '"' + x + '"';
       
   658         }
       
   659     };
       
   660 
       
   661     SimileAjax.JSON.toJSONString = function(o) {
       
   662         if (o instanceof Object) {
       
   663             return s.object(o);
       
   664         } else if (o instanceof Array) {
       
   665             return s.array(o);
    54         } else {
   666         } else {
    55             to[i] = type.apply(this, data);
   667             return o.toString();
    56         }
   668         }
    57     }
   669     };
    58     return to;
   670 
    59 };
   671     SimileAjax.JSON.parseJSON = function () {
    60 
   672         try {
    61 
   673             return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
    62 SimileAjax.Platform = new Object();
   674                     this.replace(/"(\\.|[^"\\])*"/g, ''))) &&
    63 SimileAjax.urlPrefix = baseuri();
   675                 eval('(' + this + ')');
    64 
   676         } catch (e) {
    65 window.Timeline = new Object();
   677             return false;
    66 Timeline.urlPrefix = baseuri();
   678         }
    67 window.Timeline.DateTime = window.SimileAjax.DateTime; // for backward compatibility
   679     };
    68 
       
    69 /* platform.js */
       
    70 SimileAjax.jQuery = jQuery;
       
    71 // SimileAjax.jQuery=jQuery.noConflict(true);
       
    72 if(typeof window["$"]=="undefined"){window.$=SimileAjax.jQuery;
       
    73 }SimileAjax.Platform.os={isMac:false,isWin:false,isWin32:false,isUnix:false};
       
    74 SimileAjax.Platform.browser={isIE:false,isNetscape:false,isMozilla:false,isFirefox:false,isOpera:false,isSafari:false,majorVersion:0,minorVersion:0};
       
    75 (function(){var C=navigator.appName.toLowerCase();
       
    76 var A=navigator.userAgent.toLowerCase();
       
    77 SimileAjax.Platform.os.isMac=(A.indexOf("mac")!=-1);
       
    78 SimileAjax.Platform.os.isWin=(A.indexOf("win")!=-1);
       
    79 SimileAjax.Platform.os.isWin32=SimileAjax.Platform.isWin&&(A.indexOf("95")!=-1||A.indexOf("98")!=-1||A.indexOf("nt")!=-1||A.indexOf("win32")!=-1||A.indexOf("32bit")!=-1);
       
    80 SimileAjax.Platform.os.isUnix=(A.indexOf("x11")!=-1);
       
    81 SimileAjax.Platform.browser.isIE=(C.indexOf("microsoft")!=-1);
       
    82 SimileAjax.Platform.browser.isNetscape=(C.indexOf("netscape")!=-1);
       
    83 SimileAjax.Platform.browser.isMozilla=(A.indexOf("mozilla")!=-1);
       
    84 SimileAjax.Platform.browser.isFirefox=(A.indexOf("firefox")!=-1);
       
    85 SimileAjax.Platform.browser.isOpera=(C.indexOf("opera")!=-1);
       
    86 SimileAjax.Platform.browser.isSafari=(C.indexOf("safari")!=-1);
       
    87 var E=function(G){var F=G.split(".");
       
    88 SimileAjax.Platform.browser.majorVersion=parseInt(F[0]);
       
    89 SimileAjax.Platform.browser.minorVersion=parseInt(F[1]);
       
    90 };
       
    91 var B=function(H,G,I){var F=H.indexOf(G,I);
       
    92 return F>=0?F:H.length;
       
    93 };
       
    94 if(SimileAjax.Platform.browser.isMozilla){var D=A.indexOf("mozilla/");
       
    95 if(D>=0){E(A.substring(D+8,B(A," ",D)));
       
    96 }}if(SimileAjax.Platform.browser.isIE){var D=A.indexOf("msie ");
       
    97 if(D>=0){E(A.substring(D+5,B(A,";",D)));
       
    98 }}if(SimileAjax.Platform.browser.isNetscape){var D=A.indexOf("rv:");
       
    99 if(D>=0){E(A.substring(D+3,B(A,")",D)));
       
   100 }}if(SimileAjax.Platform.browser.isFirefox){var D=A.indexOf("firefox/");
       
   101 if(D>=0){E(A.substring(D+8,B(A," ",D)));
       
   102 }}if(!("localeCompare" in String.prototype)){String.prototype.localeCompare=function(F){if(this<F){return -1;
       
   103 }else{if(this>F){return 1;
       
   104 }else{return 0;
       
   105 }}};
       
   106 }})();
       
   107 SimileAjax.Platform.getDefaultLocale=function(){return SimileAjax.Platform.clientLocale;
       
   108 };
       
   109 
       
   110 
       
   111 /* ajax.js */
       
   112 SimileAjax.ListenerQueue=function(A){this._listeners=[];
       
   113 this._wildcardHandlerName=A;
       
   114 };
       
   115 SimileAjax.ListenerQueue.prototype.add=function(A){this._listeners.push(A);
       
   116 };
       
   117 SimileAjax.ListenerQueue.prototype.remove=function(C){var B=this._listeners;
       
   118 for(var A=0;
       
   119 A<B.length;
       
   120 A++){if(B[A]==C){B.splice(A,1);
       
   121 break;
       
   122 }}};
       
   123 SimileAjax.ListenerQueue.prototype.fire=function(B,A){var D=[].concat(this._listeners);
       
   124 for(var C=0;
       
   125 C<D.length;
       
   126 C++){var E=D[C];
       
   127 if(B in E){try{E[B].apply(E,A);
       
   128 }catch(F){SimileAjax.Debug.exception("Error firing event of name "+B,F);
       
   129 }}else{if(this._wildcardHandlerName!=null&&this._wildcardHandlerName in E){try{E[this._wildcardHandlerName].apply(E,[B]);
       
   130 }catch(F){SimileAjax.Debug.exception("Error firing event of name "+B+" to wildcard handler",F);
       
   131 }}}}};
       
   132 
       
   133 
       
   134 /* data-structure.js */
       
   135 SimileAjax.Set=function(A){this._hash={};
       
   136 this._count=0;
       
   137 if(A instanceof Array){for(var B=0;
       
   138 B<A.length;
       
   139 B++){this.add(A[B]);
       
   140 }}else{if(A instanceof SimileAjax.Set){this.addSet(A);
       
   141 }}};
       
   142 SimileAjax.Set.prototype.add=function(A){if(!(A in this._hash)){this._hash[A]=true;
       
   143 this._count++;
       
   144 return true;
       
   145 }return false;
       
   146 };
       
   147 SimileAjax.Set.prototype.addSet=function(B){for(var A in B._hash){this.add(A);
       
   148 }};
       
   149 SimileAjax.Set.prototype.remove=function(A){if(A in this._hash){delete this._hash[A];
       
   150 this._count--;
       
   151 return true;
       
   152 }return false;
       
   153 };
       
   154 SimileAjax.Set.prototype.removeSet=function(B){for(var A in B._hash){this.remove(A);
       
   155 }};
       
   156 SimileAjax.Set.prototype.retainSet=function(B){for(var A in this._hash){if(!B.contains(A)){delete this._hash[A];
       
   157 this._count--;
       
   158 }}};
       
   159 SimileAjax.Set.prototype.contains=function(A){return(A in this._hash);
       
   160 };
       
   161 SimileAjax.Set.prototype.size=function(){return this._count;
       
   162 };
       
   163 SimileAjax.Set.prototype.toArray=function(){var A=[];
       
   164 for(var B in this._hash){A.push(B);
       
   165 }return A;
       
   166 };
       
   167 SimileAjax.Set.prototype.visit=function(A){for(var B in this._hash){if(A(B)==true){break;
       
   168 }}};
       
   169 SimileAjax.SortedArray=function(B,A){this._a=(A instanceof Array)?A:[];
       
   170 this._compare=B;
       
   171 };
       
   172 SimileAjax.SortedArray.prototype.add=function(C){var A=this;
       
   173 var B=this.find(function(D){return A._compare(D,C);
       
   174 });
       
   175 if(B<this._a.length){this._a.splice(B,0,C);
       
   176 }else{this._a.push(C);
       
   177 }};
       
   178 SimileAjax.SortedArray.prototype.remove=function(C){var A=this;
       
   179 var B=this.find(function(D){return A._compare(D,C);
       
   180 });
       
   181 while(B<this._a.length&&this._compare(this._a[B],C)==0){if(this._a[B]==C){this._a.splice(B,1);
       
   182 return true;
       
   183 }else{B++;
       
   184 }}return false;
       
   185 };
       
   186 SimileAjax.SortedArray.prototype.removeAll=function(){this._a=[];
       
   187 };
       
   188 SimileAjax.SortedArray.prototype.elementAt=function(A){return this._a[A];
       
   189 };
       
   190 SimileAjax.SortedArray.prototype.length=function(){return this._a.length;
       
   191 };
       
   192 SimileAjax.SortedArray.prototype.find=function(D){var B=0;
       
   193 var A=this._a.length;
       
   194 while(B<A){var C=Math.floor((B+A)/2);
       
   195 var E=D(this._a[C]);
       
   196 if(C==B){return E<0?B+1:B;
       
   197 }else{if(E<0){B=C;
       
   198 }else{A=C;
       
   199 }}}return B;
       
   200 };
       
   201 SimileAjax.SortedArray.prototype.getFirst=function(){return(this._a.length>0)?this._a[0]:null;
       
   202 };
       
   203 SimileAjax.SortedArray.prototype.getLast=function(){return(this._a.length>0)?this._a[this._a.length-1]:null;
       
   204 };
       
   205 SimileAjax.EventIndex=function(B){var A=this;
       
   206 this._unit=(B!=null)?B:SimileAjax.NativeDateUnit;
       
   207 this._events=new SimileAjax.SortedArray(function(D,C){return A._unit.compare(D.getStart(),C.getStart());
       
   208 });
       
   209 this._idToEvent={};
       
   210 this._indexed=true;
       
   211 };
       
   212 SimileAjax.EventIndex.prototype.getUnit=function(){return this._unit;
       
   213 };
       
   214 SimileAjax.EventIndex.prototype.getEvent=function(A){return this._idToEvent[A];
       
   215 };
       
   216 SimileAjax.EventIndex.prototype.add=function(A){this._events.add(A);
       
   217 this._idToEvent[A.getID()]=A;
       
   218 this._indexed=false;
       
   219 };
       
   220 SimileAjax.EventIndex.prototype.removeAll=function(){this._events.removeAll();
       
   221 this._idToEvent={};
       
   222 this._indexed=false;
       
   223 };
       
   224 SimileAjax.EventIndex.prototype.getCount=function(){return this._events.length();
       
   225 };
       
   226 SimileAjax.EventIndex.prototype.getIterator=function(A,B){if(!this._indexed){this._index();
       
   227 }return new SimileAjax.EventIndex._Iterator(this._events,A,B,this._unit);
       
   228 };
       
   229 SimileAjax.EventIndex.prototype.getReverseIterator=function(A,B){if(!this._indexed){this._index();
       
   230 }return new SimileAjax.EventIndex._ReverseIterator(this._events,A,B,this._unit);
       
   231 };
       
   232 SimileAjax.EventIndex.prototype.getAllIterator=function(){return new SimileAjax.EventIndex._AllIterator(this._events);
       
   233 };
       
   234 SimileAjax.EventIndex.prototype.getEarliestDate=function(){var A=this._events.getFirst();
       
   235 return(A==null)?null:A.getStart();
       
   236 };
       
   237 SimileAjax.EventIndex.prototype.getLatestDate=function(){var A=this._events.getLast();
       
   238 if(A==null){return null;
       
   239 }if(!this._indexed){this._index();
       
   240 }var C=A._earliestOverlapIndex;
       
   241 var B=this._events.elementAt(C).getEnd();
       
   242 for(var D=C+1;
       
   243 D<this._events.length();
       
   244 D++){B=this._unit.later(B,this._events.elementAt(D).getEnd());
       
   245 }return B;
       
   246 };
       
   247 SimileAjax.EventIndex.prototype._index=function(){var D=this._events.length();
       
   248 for(var E=0;
       
   249 E<D;
       
   250 E++){var C=this._events.elementAt(E);
       
   251 C._earliestOverlapIndex=E;
       
   252 }var G=1;
       
   253 for(var E=0;
       
   254 E<D;
       
   255 E++){var C=this._events.elementAt(E);
       
   256 var B=C.getEnd();
       
   257 G=Math.max(G,E+1);
       
   258 while(G<D){var A=this._events.elementAt(G);
       
   259 var F=A.getStart();
       
   260 if(this._unit.compare(F,B)<0){A._earliestOverlapIndex=E;
       
   261 G++;
       
   262 }else{break;
       
   263 }}}this._indexed=true;
       
   264 };
       
   265 SimileAjax.EventIndex._Iterator=function(B,A,D,C){this._events=B;
       
   266 this._startDate=A;
       
   267 this._endDate=D;
       
   268 this._unit=C;
       
   269 this._currentIndex=B.find(function(E){return C.compare(E.getStart(),A);
       
   270 });
       
   271 if(this._currentIndex-1>=0){this._currentIndex=this._events.elementAt(this._currentIndex-1)._earliestOverlapIndex;
       
   272 }this._currentIndex--;
       
   273 this._maxIndex=B.find(function(E){return C.compare(E.getStart(),D);
       
   274 });
       
   275 this._hasNext=false;
       
   276 this._next=null;
       
   277 this._findNext();
       
   278 };
       
   279 SimileAjax.EventIndex._Iterator.prototype={hasNext:function(){return this._hasNext;
       
   280 },next:function(){if(this._hasNext){var A=this._next;
       
   281 this._findNext();
       
   282 return A;
       
   283 }else{return null;
       
   284 }},_findNext:function(){var B=this._unit;
       
   285 while((++this._currentIndex)<this._maxIndex){var A=this._events.elementAt(this._currentIndex);
       
   286 if(B.compare(A.getStart(),this._endDate)<0&&B.compare(A.getEnd(),this._startDate)>0){this._next=A;
       
   287 this._hasNext=true;
       
   288 return ;
       
   289 }}this._next=null;
       
   290 this._hasNext=false;
       
   291 }};
       
   292 SimileAjax.EventIndex._ReverseIterator=function(B,A,D,C){this._events=B;
       
   293 this._startDate=A;
       
   294 this._endDate=D;
       
   295 this._unit=C;
       
   296 this._minIndex=B.find(function(E){return C.compare(E.getStart(),A);
       
   297 });
       
   298 if(this._minIndex-1>=0){this._minIndex=this._events.elementAt(this._minIndex-1)._earliestOverlapIndex;
       
   299 }this._maxIndex=B.find(function(E){return C.compare(E.getStart(),D);
       
   300 });
       
   301 this._currentIndex=this._maxIndex;
       
   302 this._hasNext=false;
       
   303 this._next=null;
       
   304 this._findNext();
       
   305 };
       
   306 SimileAjax.EventIndex._ReverseIterator.prototype={hasNext:function(){return this._hasNext;
       
   307 },next:function(){if(this._hasNext){var A=this._next;
       
   308 this._findNext();
       
   309 return A;
       
   310 }else{return null;
       
   311 }},_findNext:function(){var B=this._unit;
       
   312 while((--this._currentIndex)>=this._minIndex){var A=this._events.elementAt(this._currentIndex);
       
   313 if(B.compare(A.getStart(),this._endDate)<0&&B.compare(A.getEnd(),this._startDate)>0){this._next=A;
       
   314 this._hasNext=true;
       
   315 return ;
       
   316 }}this._next=null;
       
   317 this._hasNext=false;
       
   318 }};
       
   319 SimileAjax.EventIndex._AllIterator=function(A){this._events=A;
       
   320 this._index=0;
       
   321 };
       
   322 SimileAjax.EventIndex._AllIterator.prototype={hasNext:function(){return this._index<this._events.length();
       
   323 },next:function(){return this._index<this._events.length()?this._events.elementAt(this._index++):null;
       
   324 }};
       
   325 
       
   326 
       
   327 /* date-time.js */
       
   328 SimileAjax.DateTime=new Object();
       
   329 SimileAjax.DateTime.MILLISECOND=0;
       
   330 SimileAjax.DateTime.SECOND=1;
       
   331 SimileAjax.DateTime.MINUTE=2;
       
   332 SimileAjax.DateTime.HOUR=3;
       
   333 SimileAjax.DateTime.DAY=4;
       
   334 SimileAjax.DateTime.WEEK=5;
       
   335 SimileAjax.DateTime.MONTH=6;
       
   336 SimileAjax.DateTime.YEAR=7;
       
   337 SimileAjax.DateTime.DECADE=8;
       
   338 SimileAjax.DateTime.CENTURY=9;
       
   339 SimileAjax.DateTime.MILLENNIUM=10;
       
   340 SimileAjax.DateTime.EPOCH=-1;
       
   341 SimileAjax.DateTime.ERA=-2;
       
   342 SimileAjax.DateTime.gregorianUnitLengths=[];
       
   343 (function(){var B=SimileAjax.DateTime;
       
   344 var A=B.gregorianUnitLengths;
       
   345 A[B.MILLISECOND]=1;
       
   346 A[B.SECOND]=1000;
       
   347 A[B.MINUTE]=A[B.SECOND]*60;
       
   348 A[B.HOUR]=A[B.MINUTE]*60;
       
   349 A[B.DAY]=A[B.HOUR]*24;
       
   350 A[B.WEEK]=A[B.DAY]*7;
       
   351 A[B.MONTH]=A[B.DAY]*31;
       
   352 A[B.YEAR]=A[B.DAY]*365;
       
   353 A[B.DECADE]=A[B.YEAR]*10;
       
   354 A[B.CENTURY]=A[B.YEAR]*100;
       
   355 A[B.MILLENNIUM]=A[B.YEAR]*1000;
       
   356 })();
   680 })();
   357 SimileAjax.DateTime._dateRegexp=new RegExp("^(-?)([0-9]{4})("+["(-?([0-9]{2})(-?([0-9]{2}))?)","(-?([0-9]{3}))","(-?W([0-9]{2})(-?([1-7]))?)"].join("|")+")?$");
   681 /*==================================================
   358 SimileAjax.DateTime._timezoneRegexp=new RegExp("Z|(([-+])([0-9]{2})(:?([0-9]{2}))?)$");
   682  *  DOM Utility Functions
   359 SimileAjax.DateTime._timeRegexp=new RegExp("^([0-9]{2})(:?([0-9]{2})(:?([0-9]{2})(.([0-9]+))?)?)?$");
   683  *==================================================
   360 SimileAjax.DateTime.setIso8601Date=function(H,F){var I=F.match(SimileAjax.DateTime._dateRegexp);
   684  */
   361 if(!I){throw new Error("Invalid date string: "+F);
   685 
   362 }var B=(I[1]=="-")?-1:1;
   686 SimileAjax.DOM = new Object();
   363 var J=B*I[2];
   687 
   364 var G=I[5];
   688 SimileAjax.DOM.registerEventWithObject = function(elmt, eventName, obj, handlerName) {
   365 var C=I[7];
   689     SimileAjax.DOM.registerEvent(elmt, eventName, function(elmt2, evt, target) {
   366 var E=I[9];
   690         return obj[handlerName].call(obj, elmt2, evt, target);
   367 var A=I[11];
   691     });
   368 var M=(I[13])?I[13]:1;
   692 };
   369 H.setUTCFullYear(J);
   693 
   370 if(E){H.setUTCMonth(0);
   694 SimileAjax.DOM.registerEvent = function(elmt, eventName, handler) {
   371 H.setUTCDate(Number(E));
   695     var handler2 = function(evt) {
   372 }else{if(A){H.setUTCMonth(0);
   696         evt = (evt) ? evt : ((event) ? event : null);
   373 H.setUTCDate(1);
   697         if (evt) {
   374 var L=H.getUTCDay();
   698             var target = (evt.target) ?
   375 var K=(L)?L:7;
   699                 evt.target : ((evt.srcElement) ? evt.srcElement : null);
   376 var D=Number(M)+(7*Number(A));
   700             if (target) {
   377 if(K<=4){H.setUTCDate(D+1-K);
   701                 target = (target.nodeType == 1 || target.nodeType == 9) ?
   378 }else{H.setUTCDate(D+8-K);
   702                     target : target.parentNode;
   379 }}else{if(G){H.setUTCDate(1);
   703             }
   380 H.setUTCMonth(G-1);
   704 
   381 }if(C){H.setUTCDate(C);
   705             return handler(elmt, evt, target);
   382 }}}return H;
   706         }
   383 };
   707         return true;
   384 SimileAjax.DateTime.setIso8601Time=function(F,C){var G=C.match(SimileAjax.DateTime._timeRegexp);
   708     }
   385 if(!G){SimileAjax.Debug.warn("Invalid time string: "+C);
   709 
   386 return false;
   710     if (SimileAjax.Platform.browser.isIE) {
   387 }var A=G[1];
   711         elmt.attachEvent("on" + eventName, handler2);
   388 var E=Number((G[3])?G[3]:0);
   712     } else {
   389 var D=(G[5])?G[5]:0;
   713         elmt.addEventListener(eventName, handler2, false);
   390 var B=G[7]?(Number("0."+G[7])*1000):0;
   714     }
   391 F.setUTCHours(A);
   715 };
   392 F.setUTCMinutes(E);
   716 
   393 F.setUTCSeconds(D);
   717 SimileAjax.DOM.getPageCoordinates = function(elmt) {
   394 F.setUTCMilliseconds(B);
   718     var left = 0;
   395 return F;
   719     var top = 0;
   396 };
   720 
   397 SimileAjax.DateTime.timezoneOffset=new Date().getTimezoneOffset();
   721     if (elmt.nodeType != 1) {
   398 SimileAjax.DateTime.setIso8601=function(B,A){var D=null;
   722         elmt = elmt.parentNode;
   399 var E=(A.indexOf("T")==-1)?A.split(" "):A.split("T");
   723     }
   400 SimileAjax.DateTime.setIso8601Date(B,E[0]);
   724 
   401 if(E.length==2){var C=E[1].match(SimileAjax.DateTime._timezoneRegexp);
   725     var elmt2 = elmt;
   402 if(C){if(C[0]=="Z"){D=0;
   726     while (elmt2 != null) {
   403 }else{D=(Number(C[3])*60)+Number(C[5]);
   727         left += elmt2.offsetLeft;
   404 D*=((C[2]=="-")?1:-1);
   728         top += elmt2.offsetTop;
   405 }E[1]=E[1].substr(0,E[1].length-C[0].length);
   729         elmt2 = elmt2.offsetParent;
   406 }SimileAjax.DateTime.setIso8601Time(B,E[1]);
   730     }
   407 }if(D==null){D=B.getTimezoneOffset();
   731 
   408 }B.setTime(B.getTime()+D*60000);
   732     var body = document.body;
   409 return B;
   733     while (elmt != null && elmt != body) {
   410 };
   734         if ("scrollLeft" in elmt) {
   411 SimileAjax.DateTime.parseIso8601DateTime=function(A){try{return SimileAjax.DateTime.setIso8601(new Date(0),A);
   735             left -= elmt.scrollLeft;
   412 }catch(B){return null;
   736             top -= elmt.scrollTop;
   413 }};
   737         }
   414 SimileAjax.DateTime.parseGregorianDateTime=function(G){if(G==null){return null;
   738         elmt = elmt.parentNode;
   415 }else{if(G instanceof Date){return G;
   739     }
   416 }}var B=G.toString();
   740 
   417 if(B.length>0&&B.length<8){var C=B.indexOf(" ");
   741     return { left: left, top: top };
   418 if(C>0){var A=parseInt(B.substr(0,C));
   742 };
   419 var E=B.substr(C+1);
   743 
   420 if(E.toLowerCase()=="bc"){A=1-A;
   744 SimileAjax.DOM.getSize = function(elmt) {
   421 }}else{var A=parseInt(B);
   745 	var w = this.getStyle(elmt,"width");
   422 }var F=new Date(0);
   746 	var h = this.getStyle(elmt,"height");
   423 F.setUTCFullYear(A);
   747 	if (w.indexOf("px") > -1) w = w.replace("px","");
   424 return F;
   748 	if (h.indexOf("px") > -1) h = h.replace("px","");
   425 }try{return new Date(Date.parse(B));
   749 	return {
   426 }catch(D){return null;
   750 		w: w,
   427 }};
   751 		h: h
   428 SimileAjax.DateTime.roundDownToInterval=function(B,G,J,K,A){var D=J*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR];
   752 	}
   429 var I=new Date(B.getTime()+D);
   753 }
   430 var E=function(L){L.setUTCMilliseconds(0);
   754 
   431 L.setUTCSeconds(0);
   755 SimileAjax.DOM.getStyle = function(elmt, styleProp) {
   432 L.setUTCMinutes(0);
   756     if (elmt.currentStyle) { // IE
   433 L.setUTCHours(0);
   757         var style = elmt.currentStyle[styleProp];
   434 };
   758     } else if (window.getComputedStyle) { // standard DOM
   435 var C=function(L){E(L);
   759         var style = document.defaultView.getComputedStyle(elmt, null).getPropertyValue(styleProp);
   436 L.setUTCDate(1);
   760     } else {
   437 L.setUTCMonth(0);
   761     	var style = "";
   438 };
   762     }
   439 switch(G){case SimileAjax.DateTime.MILLISECOND:var H=I.getUTCMilliseconds();
   763     return style;
   440 I.setUTCMilliseconds(H-(H%K));
   764 }
   441 break;
   765 
   442 case SimileAjax.DateTime.SECOND:I.setUTCMilliseconds(0);
   766 SimileAjax.DOM.getEventRelativeCoordinates = function(evt, elmt) {
   443 var H=I.getUTCSeconds();
   767     if (SimileAjax.Platform.browser.isIE) {
   444 I.setUTCSeconds(H-(H%K));
   768       if (evt.type == "mousewheel") {
   445 break;
   769         var coords = SimileAjax.DOM.getPageCoordinates(elmt);
   446 case SimileAjax.DateTime.MINUTE:I.setUTCMilliseconds(0);
   770         return {
   447 I.setUTCSeconds(0);
   771           x: evt.clientX - coords.left,
   448 var H=I.getUTCMinutes();
   772           y: evt.clientY - coords.top
   449 I.setTime(I.getTime()-(H%K)*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.MINUTE]);
   773         };
   450 break;
   774       } else {
   451 case SimileAjax.DateTime.HOUR:I.setUTCMilliseconds(0);
   775         return {
   452 I.setUTCSeconds(0);
   776           x: evt.offsetX,
   453 I.setUTCMinutes(0);
   777           y: evt.offsetY
   454 var H=I.getUTCHours();
   778         };
   455 I.setUTCHours(H-(H%K));
   779       }
   456 break;
   780     } else {
   457 case SimileAjax.DateTime.DAY:E(I);
   781         var coords = SimileAjax.DOM.getPageCoordinates(elmt);
   458 break;
   782 
   459 case SimileAjax.DateTime.WEEK:E(I);
   783         if ((evt.type == "DOMMouseScroll") &&
   460 var F=(I.getUTCDay()+7-A)%7;
   784           SimileAjax.Platform.browser.isFirefox &&
   461 I.setTime(I.getTime()-F*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.DAY]);
   785           (SimileAjax.Platform.browser.majorVersion == 2)) {
   462 break;
   786           // Due to: https://bugzilla.mozilla.org/show_bug.cgi?id=352179
   463 case SimileAjax.DateTime.MONTH:E(I);
   787 
   464 I.setUTCDate(1);
   788           return {
   465 var H=I.getUTCMonth();
   789             x: evt.screenX - coords.left,
   466 I.setUTCMonth(H-(H%K));
   790             y: evt.screenY - coords.top
   467 break;
   791           };
   468 case SimileAjax.DateTime.YEAR:C(I);
   792         } else {
   469 var H=I.getUTCFullYear();
   793           return {
   470 I.setUTCFullYear(H-(H%K));
   794               x: evt.pageX - coords.left,
   471 break;
   795               y: evt.pageY - coords.top
   472 case SimileAjax.DateTime.DECADE:C(I);
   796           };
   473 I.setUTCFullYear(Math.floor(I.getUTCFullYear()/10)*10);
   797         }
   474 break;
   798     }
   475 case SimileAjax.DateTime.CENTURY:C(I);
   799 };
   476 I.setUTCFullYear(Math.floor(I.getUTCFullYear()/100)*100);
   800 
   477 break;
   801 SimileAjax.DOM.getEventPageCoordinates = function(evt) {
   478 case SimileAjax.DateTime.MILLENNIUM:C(I);
   802     if (SimileAjax.Platform.browser.isIE) {
   479 I.setUTCFullYear(Math.floor(I.getUTCFullYear()/1000)*1000);
   803         return {
   480 break;
   804             x: evt.clientX + document.body.scrollLeft,
   481 }B.setTime(I.getTime()-D);
   805             y: evt.clientY + document.body.scrollTop
   482 };
   806         };
   483 SimileAjax.DateTime.roundUpToInterval=function(D,F,C,A,B){var E=D.getTime();
   807     } else {
   484 SimileAjax.DateTime.roundDownToInterval(D,F,C,A,B);
   808         return {
   485 if(D.getTime()<E){D.setTime(D.getTime()+SimileAjax.DateTime.gregorianUnitLengths[F]*A);
   809             x: evt.pageX,
   486 }};
   810             y: evt.pageY
   487 SimileAjax.DateTime.incrementByInterval=function(B,E,A){A=(typeof A=="undefined")?0:A;
   811         };
   488 var D=A*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR];
   812     }
   489 var C=new Date(B.getTime()+D);
   813 };
   490 switch(E){case SimileAjax.DateTime.MILLISECOND:C.setTime(C.getTime()+1);
   814 
   491 break;
   815 SimileAjax.DOM.hittest = function(x, y, except) {
   492 case SimileAjax.DateTime.SECOND:C.setTime(C.getTime()+1000);
   816     return SimileAjax.DOM._hittest(document.body, x, y, except);
   493 break;
   817 };
   494 case SimileAjax.DateTime.MINUTE:C.setTime(C.getTime()+SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.MINUTE]);
   818 
   495 break;
   819 SimileAjax.DOM._hittest = function(elmt, x, y, except) {
   496 case SimileAjax.DateTime.HOUR:C.setTime(C.getTime()+SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR]);
   820     var childNodes = elmt.childNodes;
   497 break;
   821     outer: for (var i = 0; i < childNodes.length; i++) {
   498 case SimileAjax.DateTime.DAY:C.setUTCDate(C.getUTCDate()+1);
   822         var childNode = childNodes[i];
   499 break;
   823         for (var j = 0; j < except.length; j++) {
   500 case SimileAjax.DateTime.WEEK:C.setUTCDate(C.getUTCDate()+7);
   824             if (childNode == except[j]) {
   501 break;
   825                 continue outer;
   502 case SimileAjax.DateTime.MONTH:C.setUTCMonth(C.getUTCMonth()+1);
   826             }
   503 break;
   827         }
   504 case SimileAjax.DateTime.YEAR:C.setUTCFullYear(C.getUTCFullYear()+1);
   828 
   505 break;
   829         if (childNode.offsetWidth == 0 && childNode.offsetHeight == 0) {
   506 case SimileAjax.DateTime.DECADE:C.setUTCFullYear(C.getUTCFullYear()+10);
   830             /*
   507 break;
   831              *  Sometimes SPAN elements have zero width and height but
   508 case SimileAjax.DateTime.CENTURY:C.setUTCFullYear(C.getUTCFullYear()+100);
   832              *  they have children like DIVs that cover non-zero areas.
   509 break;
   833              */
   510 case SimileAjax.DateTime.MILLENNIUM:C.setUTCFullYear(C.getUTCFullYear()+1000);
   834             var hitNode = SimileAjax.DOM._hittest(childNode, x, y, except);
   511 break;
   835             if (hitNode != childNode) {
   512 }B.setTime(C.getTime()-D);
   836                 return hitNode;
   513 };
   837             }
   514 SimileAjax.DateTime.removeTimeZoneOffset=function(B,A){return new Date(B.getTime()+A*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR]);
   838         } else {
   515 };
   839             var top = 0;
   516 SimileAjax.DateTime.getTimezone=function(){var A=new Date().getTimezoneOffset();
   840             var left = 0;
   517 return A/-60;
   841 
   518 };
   842             var node = childNode;
   519 
   843             while (node) {
   520 
   844                 top += node.offsetTop;
   521 /* debug.js */
   845                 left += node.offsetLeft;
   522 SimileAjax.Debug={silent:false};
   846                 node = node.offsetParent;
   523 SimileAjax.Debug.log=function(B){var A;
   847             }
   524 if("console" in window&&"log" in window.console){A=function(C){console.log(C);
   848 
   525 };
   849             if (left <= x && top <= y && (x - left) < childNode.offsetWidth && (y - top) < childNode.offsetHeight) {
   526 }else{A=function(C){if(!SimileAjax.Debug.silent){alert(C);
   850                 return SimileAjax.DOM._hittest(childNode, x, y, except);
   527 }};
   851             } else if (childNode.nodeType == 1 && childNode.tagName == "TR") {
   528 }SimileAjax.Debug.log=A;
   852                 /*
   529 A(B);
   853                  *  Table row might have cells that span several rows.
   530 };
   854                  */
   531 SimileAjax.Debug.warn=function(B){var A;
   855                 var childNode2 = SimileAjax.DOM._hittest(childNode, x, y, except);
   532 if("console" in window&&"warn" in window.console){A=function(C){console.warn(C);
   856                 if (childNode2 != childNode) {
   533 };
   857                     return childNode2;
   534 }else{A=function(C){if(!SimileAjax.Debug.silent){alert(C);
   858                 }
   535 }};
   859             }
   536 }SimileAjax.Debug.warn=A;
   860         }
   537 A(B);
   861     }
   538 };
   862     return elmt;
   539 SimileAjax.Debug.exception=function(B,D){var A,C=SimileAjax.parseURLParameters();
   863 };
   540 if(C.errors=="throw"||SimileAjax.params.errors=="throw"){A=function(F,E){throw (F);
   864 
   541 };
   865 SimileAjax.DOM.cancelEvent = function(evt) {
   542 }else{if("console" in window&&"error" in window.console){A=function(F,E){if(E!=null){console.error(E+" %o",F);
   866     evt.returnValue = false;
   543 }else{console.error(F);
   867     evt.cancelBubble = true;
   544 }throw (F);
   868     if ("preventDefault" in evt) {
   545 };
   869         evt.preventDefault();
   546 }else{A=function(F,E){if(!SimileAjax.Debug.silent){alert("Caught exception: "+E+"\n\nDetails: "+("description" in F?F.description:F));
   870     }
   547 }throw (F);
   871 };
   548 };
   872 
   549 }}SimileAjax.Debug.exception=A;
   873 SimileAjax.DOM.appendClassName = function(elmt, className) {
   550 A(B,D);
   874     var classes = elmt.className.split(" ");
   551 };
   875     for (var i = 0; i < classes.length; i++) {
   552 SimileAjax.Debug.objectToString=function(A){return SimileAjax.Debug._objectToString(A,"");
   876         if (classes[i] == className) {
   553 };
   877             return;
   554 SimileAjax.Debug._objectToString=function(D,A){var C=A+" ";
   878         }
   555 if(typeof D=="object"){var B="{";
   879     }
   556 for(E in D){B+=C+E+": "+SimileAjax.Debug._objectToString(D[E],C)+"\n";
   880     classes.push(className);
   557 }B+=A+"}";
   881     elmt.className = classes.join(" ");
   558 return B;
   882 };
   559 }else{if(typeof D=="array"){var B="[";
   883 
   560 for(var E=0;
   884 SimileAjax.DOM.createInputElement = function(type) {
   561 E<D.length;
   885     var div = document.createElement("div");
   562 E++){B+=SimileAjax.Debug._objectToString(D[E],C)+"\n";
   886     div.innerHTML = "<input type='" + type + "' />";
   563 }B+=A+"]";
   887 
   564 return B;
   888     return div.firstChild;
   565 }else{return D;
   889 };
   566 }}};
   890 
   567 
   891 SimileAjax.DOM.createDOMFromTemplate = function(template) {
   568 
   892     var result = {};
   569 /* dom.js */
   893     result.elmt = SimileAjax.DOM._createDOMFromTemplate(template, result, null);
   570 SimileAjax.DOM=new Object();
   894 
   571 SimileAjax.DOM.registerEventWithObject=function(C,A,D,B){SimileAjax.DOM.registerEvent(C,A,function(F,E,G){return D[B].call(D,F,E,G);
   895     return result;
   572 });
   896 };
   573 };
   897 
   574 SimileAjax.DOM.registerEvent=function(C,B,D){var A=function(E){E=(E)?E:((event)?event:null);
   898 SimileAjax.DOM._createDOMFromTemplate = function(templateNode, result, parentElmt) {
   575 if(E){var F=(E.target)?E.target:((E.srcElement)?E.srcElement:null);
   899     if (templateNode == null) {
   576 if(F){F=(F.nodeType==1||F.nodeType==9)?F:F.parentNode;
   900         /*
   577 }return D(C,E,F);
   901         var node = doc.createTextNode("--null--");
   578 }return true;
   902         if (parentElmt != null) {
   579 };
   903             parentElmt.appendChild(node);
   580 if(SimileAjax.Platform.browser.isIE){C.attachEvent("on"+B,A);
   904         }
   581 }else{C.addEventListener(B,A,false);
   905         return node;
   582 }};
   906         */
   583 SimileAjax.DOM.getPageCoordinates=function(B){var E=0;
   907         return null;
   584 var D=0;
   908     } else if (typeof templateNode != "object") {
   585 if(B.nodeType!=1){B=B.parentNode;
   909         var node = document.createTextNode(templateNode);
   586 }var C=B;
   910         if (parentElmt != null) {
   587 while(C!=null){E+=C.offsetLeft;
   911             parentElmt.appendChild(node);
   588 D+=C.offsetTop;
   912         }
   589 C=C.offsetParent;
   913         return node;
   590 }var A=document.body;
   914     } else {
   591 while(B!=null&&B!=A){if("scrollLeft" in B){E-=B.scrollLeft;
   915         var elmt = null;
   592 D-=B.scrollTop;
   916         if ("tag" in templateNode) {
   593 }B=B.parentNode;
   917             var tag = templateNode.tag;
   594 }return{left:E,top:D};
   918             if (parentElmt != null) {
   595 };
   919                 if (tag == "tr") {
   596 SimileAjax.DOM.getSize=function(B){var A=this.getStyle(B,"width");
   920                     elmt = parentElmt.insertRow(parentElmt.rows.length);
   597 var C=this.getStyle(B,"height");
   921                 } else if (tag == "td") {
   598 if(A.indexOf("px")>-1){A=A.replace("px","");
   922                     elmt = parentElmt.insertCell(parentElmt.cells.length);
   599 }if(C.indexOf("px")>-1){C=C.replace("px","");
   923                 }
   600 }return{w:A,h:C};
   924             }
   601 };
   925             if (elmt == null) {
   602 SimileAjax.DOM.getStyle=function(B,A){if(B.currentStyle){var C=B.currentStyle[A];
   926                 elmt = tag == "input" ?
   603 }else{if(window.getComputedStyle){var C=document.defaultView.getComputedStyle(B,null).getPropertyValue(A);
   927                     SimileAjax.DOM.createInputElement(templateNode.type) :
   604 }else{var C="";
   928                     document.createElement(tag);
   605 }}return C;
   929 
   606 };
   930                 if (parentElmt != null) {
   607 SimileAjax.DOM.getEventRelativeCoordinates=function(A,B){if(SimileAjax.Platform.browser.isIE){if(A.type=="mousewheel"){var C=SimileAjax.DOM.getPageCoordinates(B);
   931                     parentElmt.appendChild(elmt);
   608 return{x:A.clientX-C.left,y:A.clientY-C.top};
   932                 }
   609 }else{return{x:A.offsetX,y:A.offsetY};
   933             }
   610 }}else{var C=SimileAjax.DOM.getPageCoordinates(B);
   934         } else {
   611 if((A.type=="DOMMouseScroll")&&SimileAjax.Platform.browser.isFirefox&&(SimileAjax.Platform.browser.majorVersion==2)){return{x:A.screenX-C.left,y:A.screenY-C.top};
   935             elmt = templateNode.elmt;
   612 }else{return{x:A.pageX-C.left,y:A.pageY-C.top};
   936             if (parentElmt != null) {
   613 }}};
   937                 parentElmt.appendChild(elmt);
   614 SimileAjax.DOM.getEventPageCoordinates=function(A){if(SimileAjax.Platform.browser.isIE){return{x:A.clientX+document.body.scrollLeft,y:A.clientY+document.body.scrollTop};
   938             }
   615 }else{return{x:A.pageX,y:A.pageY};
   939         }
   616 }};
   940 
   617 SimileAjax.DOM.hittest=function(A,C,B){return SimileAjax.DOM._hittest(document.body,A,C,B);
   941         for (var attribute in templateNode) {
   618 };
   942             var value = templateNode[attribute];
   619 SimileAjax.DOM._hittest=function(C,L,K,H){var M=C.childNodes;
   943 
   620 outer:for(var G=0;
   944             if (attribute == "field") {
   621 G<M.length;
   945                 result[value] = elmt;
   622 G++){var A=M[G];
   946 
   623 for(var F=0;
   947             } else if (attribute == "className") {
   624 F<H.length;
   948                 elmt.className = value;
   625 F++){if(A==H[F]){continue outer;
   949             } else if (attribute == "id") {
   626 }}if(A.offsetWidth==0&&A.offsetHeight==0){var B=SimileAjax.DOM._hittest(A,L,K,H);
   950                 elmt.id = value;
   627 if(B!=A){return B;
   951             } else if (attribute == "title") {
   628 }}else{var J=0;
   952                 elmt.title = value;
   629 var E=0;
   953             } else if (attribute == "type" && elmt.tagName == "input") {
   630 var D=A;
   954                 // do nothing
   631 while(D){J+=D.offsetTop;
   955             } else if (attribute == "style") {
   632 E+=D.offsetLeft;
   956                 for (n in value) {
   633 D=D.offsetParent;
   957                     var v = value[n];
   634 }if(E<=L&&J<=K&&(L-E)<A.offsetWidth&&(K-J)<A.offsetHeight){return SimileAjax.DOM._hittest(A,L,K,H);
   958                     if (n == "float") {
   635 }else{if(A.nodeType==1&&A.tagName=="TR"){var I=SimileAjax.DOM._hittest(A,L,K,H);
   959                         n = SimileAjax.Platform.browser.isIE ? "styleFloat" : "cssFloat";
   636 if(I!=A){return I;
   960                     }
   637 }}}}}return C;
   961                     elmt.style[n] = v;
   638 };
   962                 }
   639 SimileAjax.DOM.cancelEvent=function(A){A.returnValue=false;
   963             } else if (attribute == "children") {
   640 A.cancelBubble=true;
   964                 for (var i = 0; i < value.length; i++) {
   641 if("preventDefault" in A){A.preventDefault();
   965                     SimileAjax.DOM._createDOMFromTemplate(value[i], result, elmt);
   642 }};
   966                 }
   643 SimileAjax.DOM.appendClassName=function(C,D){var B=C.className.split(" ");
   967             } else if (attribute != "tag" && attribute != "elmt") {
   644 for(var A=0;
   968                 elmt.setAttribute(attribute, value);
   645 A<B.length;
   969             }
   646 A++){if(B[A]==D){return ;
   970         }
   647 }}B.push(D);
   971         return elmt;
   648 C.className=B.join(" ");
   972     }
   649 };
   973 }
   650 SimileAjax.DOM.createInputElement=function(A){var B=document.createElement("div");
   974 
   651 B.innerHTML="<input type='"+A+"' />";
   975 SimileAjax.DOM._cachedParent = null;
   652 return B.firstChild;
   976 SimileAjax.DOM.createElementFromString = function(s) {
   653 };
   977     if (SimileAjax.DOM._cachedParent == null) {
   654 SimileAjax.DOM.createDOMFromTemplate=function(B){var A={};
   978         SimileAjax.DOM._cachedParent = document.createElement("div");
   655 A.elmt=SimileAjax.DOM._createDOMFromTemplate(B,A,null);
   979     }
   656 return A;
   980     SimileAjax.DOM._cachedParent.innerHTML = s;
   657 };
   981     return SimileAjax.DOM._cachedParent.firstChild;
   658 SimileAjax.DOM._createDOMFromTemplate=function(A,I,E){if(A==null){return null;
   982 };
   659 }else{if(typeof A!="object"){var D=document.createTextNode(A);
   983 
   660 if(E!=null){E.appendChild(D);
   984 SimileAjax.DOM.createDOMFromString = function(root, s, fieldElmts) {
   661 }return D;
   985     var elmt = typeof root == "string" ? document.createElement(root) : root;
   662 }else{var C=null;
   986     elmt.innerHTML = s;
   663 if("tag" in A){var J=A.tag;
   987 
   664 if(E!=null){if(J=="tr"){C=E.insertRow(E.rows.length);
   988     var dom = { elmt: elmt };
   665 }else{if(J=="td"){C=E.insertCell(E.cells.length);
   989     SimileAjax.DOM._processDOMChildrenConstructedFromString(dom, elmt, fieldElmts != null ? fieldElmts : {} );
   666 }}}if(C==null){C=J=="input"?SimileAjax.DOM.createInputElement(A.type):document.createElement(J);
   990 
   667 if(E!=null){E.appendChild(C);
   991     return dom;
   668 }}}else{C=A.elmt;
   992 };
   669 if(E!=null){E.appendChild(C);
   993 
   670 }}for(var B in A){var G=A[B];
   994 SimileAjax.DOM._processDOMConstructedFromString = function(dom, elmt, fieldElmts) {
   671 if(B=="field"){I[G]=C;
   995     var id = elmt.id;
   672 }else{if(B=="className"){C.className=G;
   996     if (id != null && id.length > 0) {
   673 }else{if(B=="id"){C.id=G;
   997         elmt.removeAttribute("id");
   674 }else{if(B=="title"){C.title=G;
   998         if (id in fieldElmts) {
   675 }else{if(B=="type"&&C.tagName=="input"){}else{if(B=="style"){for(n in G){var H=G[n];
   999             var parentElmt = elmt.parentNode;
   676 if(n=="float"){n=SimileAjax.Platform.browser.isIE?"styleFloat":"cssFloat";
  1000             parentElmt.insertBefore(fieldElmts[id], elmt);
   677 }C.style[n]=H;
  1001             parentElmt.removeChild(elmt);
   678 }}else{if(B=="children"){for(var F=0;
  1002 
   679 F<G.length;
  1003             dom[id] = fieldElmts[id];
   680 F++){SimileAjax.DOM._createDOMFromTemplate(G[F],I,C);
  1004             return;
   681 }}else{if(B!="tag"&&B!="elmt"){C.setAttribute(B,G);
  1005         } else {
   682 }}}}}}}}}return C;
  1006             dom[id] = elmt;
   683 }}};
  1007         }
   684 SimileAjax.DOM._cachedParent=null;
  1008     }
   685 SimileAjax.DOM.createElementFromString=function(A){if(SimileAjax.DOM._cachedParent==null){SimileAjax.DOM._cachedParent=document.createElement("div");
  1009 
   686 }SimileAjax.DOM._cachedParent.innerHTML=A;
  1010     if (elmt.hasChildNodes()) {
   687 return SimileAjax.DOM._cachedParent.firstChild;
  1011         SimileAjax.DOM._processDOMChildrenConstructedFromString(dom, elmt, fieldElmts);
   688 };
  1012     }
   689 SimileAjax.DOM.createDOMFromString=function(A,C,D){var B=typeof A=="string"?document.createElement(A):A;
  1013 };
   690 B.innerHTML=C;
  1014 
   691 var E={elmt:B};
  1015 SimileAjax.DOM._processDOMChildrenConstructedFromString = function(dom, elmt, fieldElmts) {
   692 SimileAjax.DOM._processDOMChildrenConstructedFromString(E,B,D!=null?D:{});
  1016     var node = elmt.firstChild;
   693 return E;
  1017     while (node != null) {
   694 };
  1018         var node2 = node.nextSibling;
   695 SimileAjax.DOM._processDOMConstructedFromString=function(D,A,B){var E=A.id;
  1019         if (node.nodeType == 1) {
   696 if(E!=null&&E.length>0){A.removeAttribute("id");
  1020             SimileAjax.DOM._processDOMConstructedFromString(dom, node, fieldElmts);
   697 if(E in B){var C=A.parentNode;
  1021         }
   698 C.insertBefore(B[E],A);
  1022         node = node2;
   699 C.removeChild(A);
  1023     }
   700 D[E]=B[E];
  1024 };
   701 return ;
  1025 /**
   702 }else{D[E]=A;
  1026  * @fileOverview Graphics utility functions and constants
   703 }}if(A.hasChildNodes()){SimileAjax.DOM._processDOMChildrenConstructedFromString(D,A,B);
  1027  * @name SimileAjax.Graphics
   704 }};
  1028  */
   705 SimileAjax.DOM._processDOMChildrenConstructedFromString=function(E,B,D){var C=B.firstChild;
  1029 
   706 while(C!=null){var A=C.nextSibling;
  1030 SimileAjax.Graphics = new Object();
   707 if(C.nodeType==1){SimileAjax.DOM._processDOMConstructedFromString(E,C,D);
  1031 
   708 }C=A;
  1032 /**
   709 }};
  1033  * A boolean value indicating whether PNG translucency is supported on the
   710 
  1034  * user's browser or not.
   711 
  1035  *
   712 /* graphics.js */
  1036  * @type Boolean
   713 SimileAjax.Graphics=new Object();
  1037  */
   714 SimileAjax.Graphics.pngIsTranslucent=(!SimileAjax.Platform.browser.isIE)||(SimileAjax.Platform.browser.majorVersion>6);
  1038 SimileAjax.Graphics.pngIsTranslucent = (!SimileAjax.Platform.browser.isIE) || (SimileAjax.Platform.browser.majorVersion > 6);
   715 SimileAjax.Graphics._createTranslucentImage1=function(A,C){var B=document.createElement("img");
  1039 if (!SimileAjax.Graphics.pngIsTranslucent) {
   716 B.setAttribute("src",A);
  1040     SimileAjax.includeCssFile(document, SimileAjax.urlPrefix + "styles/graphics-ie6.css");
   717 if(C!=null){B.style.verticalAlign=C;
  1041 }
   718 }return B;
  1042 
   719 };
  1043 /*==================================================
   720 SimileAjax.Graphics._createTranslucentImage2=function(A,C){var B=document.createElement("img");
  1044  *  Opacity, translucency
   721 B.style.width="1px";
  1045  *==================================================
   722 B.style.height="1px";
  1046  */
   723 B.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+A+"', sizingMethod='image')";
  1047 SimileAjax.Graphics._createTranslucentImage1 = function(url, verticalAlign) {
   724 B.style.verticalAlign=(C!=null)?C:"middle";
  1048     var elmt = document.createElement("img");
   725 return B;
  1049     elmt.setAttribute("src", url);
   726 };
  1050     if (verticalAlign != null) {
   727 SimileAjax.Graphics.createTranslucentImage=SimileAjax.Graphics.pngIsTranslucent?SimileAjax.Graphics._createTranslucentImage1:SimileAjax.Graphics._createTranslucentImage2;
  1051         elmt.style.verticalAlign = verticalAlign;
   728 SimileAjax.Graphics._createTranslucentImageHTML1=function(A,B){return'<img src="'+A+'"'+(B!=null?' style="vertical-align: '+B+';"':"")+" />";
  1052     }
   729 };
  1053     return elmt;
   730 SimileAjax.Graphics._createTranslucentImageHTML2=function(A,C){var B="width: 1px; height: 1px; filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+A+"', sizingMethod='image');"+(C!=null?" vertical-align: "+C+";":"");
  1054 };
   731 return"<img src='"+A+"' style=\""+B+'" />';
  1055 SimileAjax.Graphics._createTranslucentImage2 = function(url, verticalAlign) {
   732 };
  1056     var elmt = document.createElement("img");
   733 SimileAjax.Graphics.createTranslucentImageHTML=SimileAjax.Graphics.pngIsTranslucent?SimileAjax.Graphics._createTranslucentImageHTML1:SimileAjax.Graphics._createTranslucentImageHTML2;
  1057     elmt.style.width = "1px";  // just so that IE will calculate the size property
   734 SimileAjax.Graphics.setOpacity=function(B,A){if(SimileAjax.Platform.browser.isIE){B.style.filter="progid:DXImageTransform.Microsoft.Alpha(Style=0,Opacity="+A+")";
  1058     elmt.style.height = "1px";
   735 }else{var C=(A/100).toString();
  1059     elmt.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + url +"', sizingMethod='image')";
   736 B.style.opacity=C;
  1060     elmt.style.verticalAlign = (verticalAlign != null) ? verticalAlign : "middle";
   737 B.style.MozOpacity=C;
  1061     return elmt;
   738 }};
  1062 };
   739 SimileAjax.Graphics._bubbleMargins={top:33,bottom:42,left:33,right:40};
  1063 
   740 SimileAjax.Graphics._arrowOffsets={top:0,bottom:9,left:1,right:8};
  1064 /**
   741 SimileAjax.Graphics._bubblePadding=15;
  1065  * Creates a DOM element for an <code>img</code> tag using the URL given. This
   742 SimileAjax.Graphics._bubblePointOffset=6;
  1066  * is a convenience method that automatically includes the necessary CSS to
   743 SimileAjax.Graphics._halfArrowWidth=18;
  1067  * allow for translucency, even on IE.
   744 SimileAjax.Graphics.createBubbleForContentAndPoint=function(F,D,C,A,B,E){if(typeof A!="number"){A=300;
  1068  *
   745 }if(typeof E!="number"){E=0;
  1069  * @function
   746 }F.style.position="absolute";
  1070  * @param {String} url the URL to the image
   747 F.style.left="-5000px";
  1071  * @param {String} verticalAlign the CSS value for the image's vertical-align
   748 F.style.top="0px";
  1072  * @return {Element} a DOM element containing the <code>img</code> tag
   749 F.style.width=A+"px";
  1073  */
   750 document.body.appendChild(F);
  1074 SimileAjax.Graphics.createTranslucentImage = SimileAjax.Graphics.pngIsTranslucent ?
   751 window.setTimeout(function(){var J=F.scrollWidth+10;
  1075     SimileAjax.Graphics._createTranslucentImage1 :
   752 var G=F.scrollHeight+10;
  1076     SimileAjax.Graphics._createTranslucentImage2;
   753 var I=0;
  1077 
   754 if(E>0&&G>E){G=E;
  1078 SimileAjax.Graphics._createTranslucentImageHTML1 = function(url, verticalAlign) {
   755 I=J-25;
  1079     return "<img src=\"" + url + "\"" +
   756 }var H=SimileAjax.Graphics.createBubbleForPoint(D,C,J,G,B);
  1080         (verticalAlign != null ? " style=\"vertical-align: " + verticalAlign + ";\"" : "") +
   757 document.body.removeChild(F);
  1081         " />";
   758 F.style.position="static";
  1082 };
   759 F.style.left="";
  1083 SimileAjax.Graphics._createTranslucentImageHTML2 = function(url, verticalAlign) {
   760 F.style.top="";
  1084     var style =
   761 if(I>0){var K=document.createElement("div");
  1085         "width: 1px; height: 1px; " +
   762 F.style.width="";
  1086         "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + url +"', sizingMethod='image');" +
   763 K.style.width=I+"px";
  1087         (verticalAlign != null ? " vertical-align: " + verticalAlign + ";" : "");
   764 K.appendChild(F);
  1088 
   765 H.content.appendChild(K);
  1089     return "<img src='" + url + "' style=\"" + style + "\" />";
   766 }else{F.style.width=J+"px";
  1090 };
   767 H.content.appendChild(F);
  1091 
   768 }},200);
  1092 /**
   769 };
  1093  * Creates an HTML string for an <code>img</code> tag using the URL given.
   770 SimileAjax.Graphics.createBubbleForPoint=function(C,B,N,R,F){function T(){if(typeof window.innerHeight=="number"){return{w:window.innerWidth,h:window.innerHeight};
  1094  * This is a convenience method that automatically includes the necessary CSS
   771 }else{if(document.documentElement&&document.documentElement.clientHeight){return{w:document.documentElement.clientWidth,h:document.documentElement.clientHeight};
  1095  * to allow for translucency, even on IE.
   772 }else{if(document.body&&document.body.clientHeight){return{w:document.body.clientWidth,h:document.body.clientHeight};
  1096  *
   773 }}}}var L=function(){if(!M._closed){document.body.removeChild(M._div);
  1097  * @function
   774 M._doc=null;
  1098  * @param {String} url the URL to the image
   775 M._div=null;
  1099  * @param {String} verticalAlign the CSS value for the image's vertical-align
   776 M._content=null;
  1100  * @return {String} a string containing the <code>img</code> tag
   777 M._closed=true;
  1101  */
   778 }};
  1102 SimileAjax.Graphics.createTranslucentImageHTML = SimileAjax.Graphics.pngIsTranslucent ?
   779 var M={_closed:false};
  1103     SimileAjax.Graphics._createTranslucentImageHTML1 :
   780 var O=T();
  1104     SimileAjax.Graphics._createTranslucentImageHTML2;
   781 var H=O.w;
  1105 
   782 var G=O.h;
  1106 /**
   783 var D=SimileAjax.Graphics._bubbleMargins;
  1107  * Sets the opacity on the given DOM element.
   784 N=parseInt(N,10);
  1108  *
   785 R=parseInt(R,10);
  1109  * @param {Element} elmt the DOM element to set the opacity on
   786 var P=D.left+N+D.right;
  1110  * @param {Number} opacity an integer from 0 to 100 specifying the opacity
   787 var U=D.top+R+D.bottom;
  1111  */
   788 var Q=SimileAjax.Graphics.pngIsTranslucent;
  1112 SimileAjax.Graphics.setOpacity = function(elmt, opacity) {
   789 var J=SimileAjax.urlPrefix;
  1113     if (SimileAjax.Platform.browser.isIE) {
   790 var A=function(Z,Y,a,X){Z.style.position="absolute";
  1114         elmt.style.filter = "progid:DXImageTransform.Microsoft.Alpha(Style=0,Opacity=" + opacity + ")";
   791 Z.style.width=a+"px";
  1115     } else {
   792 Z.style.height=X+"px";
  1116         var o = (opacity / 100).toString();
   793 if(Q){Z.style.background="url("+Y+")";
  1117         elmt.style.opacity = o;
   794 }else{Z.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+Y+"', sizingMethod='crop')";
  1118         elmt.style.MozOpacity = o;
   795 }};
  1119     }
   796 var K=document.createElement("div");
  1120 };
   797 K.style.width=P+"px";
  1121 
   798 K.style.height=U+"px";
  1122 /*==================================================
   799 K.style.position="absolute";
  1123  *  Bubble
   800 K.style.zIndex=1000;
  1124  *==================================================
   801 var W=SimileAjax.WindowManager.pushLayer(L,true,K);
  1125  */
   802 M._div=K;
  1126 
   803 M.close=function(){SimileAjax.WindowManager.popLayer(W);
  1127 SimileAjax.Graphics.bubbleConfig = {
   804 };
  1128     containerCSSClass:              "simileAjax-bubble-container",
   805 var I=document.createElement("div");
  1129     innerContainerCSSClass:         "simileAjax-bubble-innerContainer",
   806 I.style.width="100%";
  1130     contentContainerCSSClass:       "simileAjax-bubble-contentContainer",
   807 I.style.height="100%";
  1131 
   808 I.style.position="relative";
  1132     borderGraphicSize:              50,
   809 K.appendChild(I);
  1133     borderGraphicCSSClassPrefix:    "simileAjax-bubble-border-",
   810 var S=function(Z,c,b,a,Y){var X=document.createElement("div");
  1134 
   811 X.style.left=c+"px";
  1135     arrowGraphicTargetOffset:       33,  // from tip of arrow to the side of the graphic that touches the content of the bubble
   812 X.style.top=b+"px";
  1136     arrowGraphicLength:             100, // dimension of arrow graphic along the direction that the arrow points
   813 A(X,Z,a,Y);
  1137     arrowGraphicWidth:              49,  // dimension of arrow graphic perpendicular to the direction that the arrow points
   814 I.appendChild(X);
  1138     arrowGraphicCSSClassPrefix:     "simileAjax-bubble-arrow-",
   815 };
  1139 
   816 S(J+"data/timeline/bubble-top-left.png",0,0,D.left,D.top);
  1140     closeGraphicCSSClass:           "simileAjax-bubble-close",
   817 S(J+"data/timeline/bubble-top.png",D.left,0,N,D.top);
  1141 
   818 S(J+"data/timeline/bubble-top-right.png",D.left+N,0,D.right,D.top);
  1142     extraPadding:                   20
   819 S(J+"data/timeline/bubble-left.png",0,D.top,D.left,R);
  1143 };
   820 S(J+"data/timeline/bubble-right.png",D.left+N,D.top,D.right,R);
  1144 
   821 S(J+"data/timeline/bubble-bottom-left.png",0,D.top+R,D.left,D.bottom);
  1145 /**
   822 S(J+"data/timeline/bubble-bottom.png",D.left,D.top+R,N,D.bottom);
  1146  * Creates a nice, rounded bubble popup with the given content in a div,
   823 S(J+"data/timeline/bubble-bottom-right.png",D.left+N,D.top+R,D.right,D.bottom);
  1147  * page coordinates and a suggested width. The bubble will point to the
   824 var V=document.createElement("div");
  1148  * location on the page as described by pageX and pageY.  All measurements
   825 V.style.left=(P-D.right+SimileAjax.Graphics._bubblePadding-16-2)+"px";
  1149  * should be given in pixels.
   826 V.style.top=(D.top-SimileAjax.Graphics._bubblePadding+1)+"px";
  1150  *
   827 V.style.cursor="pointer";
  1151  * @param {Element} the content div
   828 A(V,J+"data/timeline/close-button.png",16,16);
  1152  * @param {Number} pageX the x coordinate of the point to point to
   829 SimileAjax.WindowManager.registerEventWithObject(V,"click",M,"close");
  1153  * @param {Number} pageY the y coordinate of the point to point to
   830 I.appendChild(V);
  1154  * @param {Number} contentWidth a suggested width of the content
   831 var E=document.createElement("div");
  1155  * @param {String} orientation a string ("top", "bottom", "left", or "right")
   832 E.style.position="absolute";
  1156  *   that describes the orientation of the arrow on the bubble
   833 E.style.left=D.left+"px";
  1157  * @param {Number} maxHeight. Add a scrollbar div if bubble would be too tall.
   834 E.style.top=D.top+"px";
  1158  *   Default of 0 or null means no maximum
   835 E.style.width=N+"px";
  1159  */
   836 E.style.height=R+"px";
  1160 SimileAjax.Graphics.createBubbleForContentAndPoint = function(
   837 E.style.overflow="auto";
  1161        div, pageX, pageY, contentWidth, orientation, maxHeight) {
   838 E.style.background="white";
  1162     if (typeof contentWidth != "number") {
   839 I.appendChild(E);
  1163         contentWidth = 300;
   840 M.content=E;
  1164     }
   841 (function(){if(C-SimileAjax.Graphics._halfArrowWidth-SimileAjax.Graphics._bubblePadding>0&&C+SimileAjax.Graphics._halfArrowWidth+SimileAjax.Graphics._bubblePadding<H){var Z=C-Math.round(N/2)-D.left;
  1165     if (typeof maxHeight != "number") {
   842 Z=C<(H/2)?Math.max(Z,-(D.left-SimileAjax.Graphics._bubblePadding)):Math.min(Z,H+(D.right-SimileAjax.Graphics._bubblePadding)-P);
  1166         maxHeight = 0;
   843 if((F&&F=="top")||(!F&&(B-SimileAjax.Graphics._bubblePointOffset-U>0))){var X=document.createElement("div");
  1167     }
   844 X.style.left=(C-SimileAjax.Graphics._halfArrowWidth-Z)+"px";
  1168 
   845 X.style.top=(D.top+R)+"px";
  1169     div.style.position = "absolute";
   846 A(X,J+"data/timeline/bubble-bottom-arrow.png",37,D.bottom);
  1170     div.style.left = "-5000px";
   847 I.appendChild(X);
  1171     div.style.top = "0px";
   848 K.style.left=Z+"px";
  1172     div.style.width = contentWidth + "px";
   849 K.style.top=(B-SimileAjax.Graphics._bubblePointOffset-U+SimileAjax.Graphics._arrowOffsets.bottom)+"px";
  1173     document.body.appendChild(div);
   850 return ;
  1174 
   851 }else{if((F&&F=="bottom")||(!F&&(B+SimileAjax.Graphics._bubblePointOffset+U<G))){var X=document.createElement("div");
  1175     window.setTimeout(function() {
   852 X.style.left=(C-SimileAjax.Graphics._halfArrowWidth-Z)+"px";
  1176         var width = div.scrollWidth + 10;
   853 X.style.top="0px";
  1177         var height = div.scrollHeight + 10;
   854 A(X,J+"data/timeline/bubble-top-arrow.png",37,D.top);
  1178         var scrollDivW = 0; // width of the possible inner container when we want vertical scrolling
   855 I.appendChild(X);
  1179         if (maxHeight > 0 && height > maxHeight) {
   856 K.style.left=Z+"px";
  1180           height = maxHeight;
   857 K.style.top=(B+SimileAjax.Graphics._bubblePointOffset-SimileAjax.Graphics._arrowOffsets.top)+"px";
  1181           scrollDivW = width - 25;
   858 return ;
  1182         }
   859 }}}var Y=B-Math.round(R/2)-D.top;
  1183 
   860 Y=B<(G/2)?Math.max(Y,-(D.top-SimileAjax.Graphics._bubblePadding)):Math.min(Y,G+(D.bottom-SimileAjax.Graphics._bubblePadding)-U);
  1184         var bubble = SimileAjax.Graphics.createBubbleForPoint(pageX, pageY, width, height, orientation);
   861 if((F&&F=="left")||(!F&&(C-SimileAjax.Graphics._bubblePointOffset-P>0))){var X=document.createElement("div");
  1185 
   862 X.style.left=(D.left+N)+"px";
  1186         document.body.removeChild(div);
   863 X.style.top=(B-SimileAjax.Graphics._halfArrowWidth-Y)+"px";
  1187         div.style.position = "static";
   864 A(X,J+"data/timeline/bubble-right-arrow.png",D.right,37);
  1188         div.style.left = "";
   865 I.appendChild(X);
  1189         div.style.top = "";
   866 K.style.left=(C-SimileAjax.Graphics._bubblePointOffset-P+SimileAjax.Graphics._arrowOffsets.right)+"px";
  1190 
   867 K.style.top=Y+"px";
  1191         // create a scroll div if needed
   868 }else{if((F&&F=="right")||(!F&&(C-SimileAjax.Graphics._bubblePointOffset-P<H))){var X=document.createElement("div");
  1192         if (scrollDivW > 0) {
   869 X.style.left="0px";
  1193           var scrollDiv = document.createElement("div");
   870 X.style.top=(B-SimileAjax.Graphics._halfArrowWidth-Y)+"px";
  1194           div.style.width = "";
   871 A(X,J+"data/timeline/bubble-left-arrow.png",D.left,37);
  1195           scrollDiv.style.width = scrollDivW + "px";
   872 I.appendChild(X);
  1196           scrollDiv.appendChild(div);
   873 K.style.left=(C+SimileAjax.Graphics._bubblePointOffset-SimileAjax.Graphics._arrowOffsets.left)+"px";
  1197           bubble.content.appendChild(scrollDiv);
   874 K.style.top=Y+"px";
  1198         } else {
   875 }}})();
  1199           div.style.width = width + "px";
   876 document.body.appendChild(K);
  1200           bubble.content.appendChild(div);
   877 return M;
  1201         }
   878 };
  1202     }, 200);
   879 SimileAjax.Graphics.createMessageBubble=function(H){var G=H.createElement("div");
  1203 };
   880 if(SimileAjax.Graphics.pngIsTranslucent){var I=H.createElement("div");
  1204 
   881 I.style.height="33px";
  1205 /**
   882 I.style.background="url("+SimileAjax.urlPrefix+"data/timeline/message-top-left.png) top left no-repeat";
  1206  * Creates a nice, rounded bubble popup with the given page coordinates and
   883 I.style.paddingLeft="44px";
  1207  * content dimensions.  The bubble will point to the location on the page
   884 G.appendChild(I);
  1208  * as described by pageX and pageY.  All measurements should be given in
   885 var C=H.createElement("div");
  1209  * pixels.
   886 C.style.height="33px";
  1210  *
   887 C.style.background="url("+SimileAjax.urlPrefix+"data/timeline/message-top-right.png) top right no-repeat";
  1211  * @param {Number} pageX the x coordinate of the point to point to
   888 I.appendChild(C);
  1212  * @param {Number} pageY the y coordinate of the point to point to
   889 var F=H.createElement("div");
  1213  * @param {Number} contentWidth the width of the content box in the bubble
   890 F.style.background="url("+SimileAjax.urlPrefix+"data/timeline/message-left.png) top left repeat-y";
  1214  * @param {Number} contentHeight the height of the content box in the bubble
   891 F.style.paddingLeft="44px";
  1215  * @param {String} orientation a string ("top", "bottom", "left", or "right")
   892 G.appendChild(F);
  1216  *   that describes the orientation of the arrow on the bubble
   893 var A=H.createElement("div");
  1217  * @return {Element} a DOM element for the newly created bubble
   894 A.style.background="url("+SimileAjax.urlPrefix+"data/timeline/message-right.png) top right repeat-y";
  1218  */
   895 A.style.paddingRight="44px";
  1219 SimileAjax.Graphics.createBubbleForPoint = function(pageX, pageY, contentWidth, contentHeight, orientation) {
   896 F.appendChild(A);
  1220     contentWidth = parseInt(contentWidth, 10); // harden against bad input bugs
   897 var D=H.createElement("div");
  1221     contentHeight = parseInt(contentHeight, 10); // getting numbers-as-strings
   898 A.appendChild(D);
  1222 
   899 var B=H.createElement("div");
  1223     var bubbleConfig = SimileAjax.Graphics.bubbleConfig;
   900 B.style.height="55px";
  1224     var pngTransparencyClassSuffix =
   901 B.style.background="url("+SimileAjax.urlPrefix+"data/timeline/message-bottom-left.png) bottom left no-repeat";
  1225         SimileAjax.Graphics.pngIsTranslucent ? "pngTranslucent" : "pngNotTranslucent";
   902 B.style.paddingLeft="44px";
  1226 
   903 G.appendChild(B);
  1227     var bubbleWidth = contentWidth + 2 * bubbleConfig.borderGraphicSize;
   904 var E=H.createElement("div");
  1228     var bubbleHeight = contentHeight + 2 * bubbleConfig.borderGraphicSize;
   905 E.style.height="55px";
  1229 
   906 E.style.background="url("+SimileAjax.urlPrefix+"data/timeline/message-bottom-right.png) bottom right no-repeat";
  1230     var generatePngSensitiveClass = function(className) {
   907 B.appendChild(E);
  1231         return className + " " + className + "-" + pngTransparencyClassSuffix;
   908 }else{G.style.border="2px solid #7777AA";
  1232     };
   909 G.style.padding="20px";
  1233 
   910 G.style.background="white";
  1234     /*
   911 SimileAjax.Graphics.setOpacity(G,90);
  1235      *  Render container divs
   912 var D=H.createElement("div");
  1236      */
   913 G.appendChild(D);
  1237     var div = document.createElement("div");
   914 }return{containerDiv:G,contentDiv:D};
  1238     div.className = generatePngSensitiveClass(bubbleConfig.containerCSSClass);
   915 };
  1239     div.style.width = contentWidth + "px";
   916 SimileAjax.Graphics.createAnimation=function(B,E,D,C,A){return new SimileAjax.Graphics._Animation(B,E,D,C,A);
  1240     div.style.height = contentHeight + "px";
   917 };
  1241 
   918 SimileAjax.Graphics._Animation=function(B,E,D,C,A){this.f=B;
  1242     var divInnerContainer = document.createElement("div");
   919 this.cont=(typeof A=="function")?A:function(){};
  1243     divInnerContainer.className = generatePngSensitiveClass(bubbleConfig.innerContainerCSSClass);
   920 this.from=E;
  1244     div.appendChild(divInnerContainer);
   921 this.to=D;
  1245 
   922 this.current=E;
  1246     /*
   923 this.duration=C;
  1247      *  Create layer for bubble
   924 this.start=new Date().getTime();
  1248      */
   925 this.timePassed=0;
  1249     var close = function() {
   926 };
  1250         if (!bubble._closed) {
   927 SimileAjax.Graphics._Animation.prototype.run=function(){var A=this;
  1251             document.body.removeChild(bubble._div);
   928 window.setTimeout(function(){A.step();
  1252             bubble._doc = null;
   929 },50);
  1253             bubble._div = null;
   930 };
  1254             bubble._content = null;
   931 SimileAjax.Graphics._Animation.prototype.step=function(){this.timePassed+=50;
  1255             bubble._closed = true;
   932 var B=this.timePassed/this.duration;
  1256         }
   933 var A=-Math.cos(B*Math.PI)/2+0.5;
  1257     }
   934 var D=A*(this.to-this.from)+this.from;
  1258     var bubble = { _closed: false };
   935 try{this.f(D,D-this.current);
  1259     var layer = SimileAjax.WindowManager.pushLayer(close, true, div);
   936 }catch(C){}this.current=D;
  1260     bubble._div = div;
   937 if(this.timePassed<this.duration){this.run();
  1261     bubble.close = function() { SimileAjax.WindowManager.popLayer(layer); }
   938 }else{this.f(this.to,0);
  1262 
   939 this["cont"]();
  1263     /*
   940 }};
  1264      *  Render border graphics
   941 SimileAjax.Graphics.createStructuredDataCopyButton=function(F,D,A,E){var G=document.createElement("div");
  1265      */
   942 G.style.position="relative";
  1266     var createBorder = function(classNameSuffix) {
   943 G.style.display="inline";
  1267         var divBorderGraphic = document.createElement("div");
   944 G.style.width=D+"px";
  1268         divBorderGraphic.className = generatePngSensitiveClass(bubbleConfig.borderGraphicCSSClassPrefix + classNameSuffix);
   945 G.style.height=A+"px";
  1269         divInnerContainer.appendChild(divBorderGraphic);
   946 G.style.overflow="hidden";
  1270     };
   947 G.style.margin="2px";
  1271     createBorder("top-left");
   948 if(SimileAjax.Graphics.pngIsTranslucent){G.style.background="url("+F+") no-repeat";
  1272     createBorder("top-right");
   949 }else{G.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+F+"', sizingMethod='image')";
  1273     createBorder("bottom-left");
   950 }var C;
  1274     createBorder("bottom-right");
   951 if(SimileAjax.Platform.browser.isIE){C="filter:alpha(opacity=0)";
  1275     createBorder("left");
   952 }else{C="opacity: 0";
  1276     createBorder("right");
   953 }G.innerHTML="<textarea rows='1' autocomplete='off' value='none' style='"+C+"' />";
  1277     createBorder("top");
   954 var B=G.firstChild;
  1278     createBorder("bottom");
   955 B.style.width=D+"px";
  1279 
   956 B.style.height=A+"px";
  1280     /*
   957 B.onmousedown=function(H){H=(H)?H:((event)?event:null);
  1281      *  Render content
   958 if(H.button==2){B.value=E();
  1282      */
   959 B.select();
  1283     var divContentContainer = document.createElement("div");
   960 }};
  1284     divContentContainer.className = generatePngSensitiveClass(bubbleConfig.contentContainerCSSClass);
   961 return G;
  1285     divInnerContainer.appendChild(divContentContainer);
   962 };
  1286     bubble.content = divContentContainer;
   963 SimileAjax.Graphics.getWidthHeight=function(C){var A,B;
  1287 
   964 if(C.getBoundingClientRect==null){A=C.offsetWidth;
  1288     /*
   965 B=C.offsetHeight;
  1289      *  Render close button
   966 }else{var D=C.getBoundingClientRect();
  1290      */
   967 A=Math.ceil(D.right-D.left);
  1291     var divClose = document.createElement("div");
   968 B=Math.ceil(D.bottom-D.top);
  1292     divClose.className = generatePngSensitiveClass(bubbleConfig.closeGraphicCSSClass);
   969 }return{width:A,height:B};
  1293     divInnerContainer.appendChild(divClose);
   970 };
  1294     SimileAjax.WindowManager.registerEventWithObject(divClose, "click", bubble, "close");
   971 SimileAjax.Graphics.getFontRenderingContext=function(A,B){return new SimileAjax.Graphics._FontRenderingContext(A,B);
  1295 
   972 };
  1296     (function() {
   973 SimileAjax.Graphics._FontRenderingContext=function(A,B){this._elmt=A;
  1297         var dims = SimileAjax.Graphics.getWindowDimensions();
   974 this._elmt.style.visibility="hidden";
  1298         var docWidth = dims.w;
   975 if(typeof B=="string"){this._elmt.style.width=B;
  1299         var docHeight = dims.h;
   976 }else{if(typeof B=="number"){this._elmt.style.width=B+"px";
  1300 
   977 }}};
  1301         var halfArrowGraphicWidth = Math.ceil(bubbleConfig.arrowGraphicWidth / 2);
   978 SimileAjax.Graphics._FontRenderingContext.prototype.dispose=function(){this._elmt=null;
  1302 
   979 };
  1303         var createArrow = function(classNameSuffix) {
   980 SimileAjax.Graphics._FontRenderingContext.prototype.update=function(){this._elmt.innerHTML="A";
  1304             var divArrowGraphic = document.createElement("div");
   981 this._lineHeight=this._elmt.offsetHeight;
  1305             divArrowGraphic.className = generatePngSensitiveClass(bubbleConfig.arrowGraphicCSSClassPrefix + "point-" + classNameSuffix);
   982 };
  1306             divInnerContainer.appendChild(divArrowGraphic);
   983 SimileAjax.Graphics._FontRenderingContext.prototype.computeSize=function(D,C){var B=this._elmt;
  1307             return divArrowGraphic;
   984 B.innerHTML=D;
  1308         };
   985 B.className=C===undefined?"":C;
  1309 
   986 var A=SimileAjax.Graphics.getWidthHeight(B);
  1310         if (pageX - halfArrowGraphicWidth - bubbleConfig.borderGraphicSize - bubbleConfig.extraPadding > 0 &&
   987 B.className="";
  1311             pageX + halfArrowGraphicWidth + bubbleConfig.borderGraphicSize + bubbleConfig.extraPadding < docWidth) {
   988 return A;
  1312 
   989 };
  1313             /*
   990 SimileAjax.Graphics._FontRenderingContext.prototype.getLineHeight=function(){return this._lineHeight;
  1314              *  Bubble can be positioned above or below the target point.
   991 };
  1315              */
   992 
  1316 
   993 
  1317             var left = pageX - Math.round(contentWidth / 2);
   994 /* history.js */
  1318             left = pageX < (docWidth / 2) ?
   995 SimileAjax.History={maxHistoryLength:10,historyFile:"__history__.html",enabled:true,_initialized:false,_listeners:new SimileAjax.ListenerQueue(),_actions:[],_baseIndex:0,_currentIndex:0,_plainDocumentTitle:document.title};
  1319                 Math.max(left, bubbleConfig.extraPadding + bubbleConfig.borderGraphicSize) :
   996 SimileAjax.History.formatHistoryEntryTitle=function(A){return SimileAjax.History._plainDocumentTitle+" {"+A+"}";
  1320                 Math.min(left, docWidth - bubbleConfig.extraPadding - bubbleConfig.borderGraphicSize - contentWidth);
   997 };
  1321 
   998 SimileAjax.History.initialize=function(){if(SimileAjax.History._initialized){return ;
  1322             if ((orientation && orientation == "top") ||
   999 }if(SimileAjax.History.enabled){var A=document.createElement("iframe");
  1323                 (!orientation &&
  1000 A.id="simile-ajax-history";
  1324                     (pageY
  1001 A.style.position="absolute";
  1325                         - bubbleConfig.arrowGraphicTargetOffset
  1002 A.style.width="10px";
  1326                         - contentHeight
  1003 A.style.height="10px";
  1327                         - bubbleConfig.borderGraphicSize
  1004 A.style.top="0px";
  1328                         - bubbleConfig.extraPadding > 0))) {
  1005 A.style.left="0px";
  1329 
  1006 A.style.visibility="hidden";
  1330                 /*
  1007 A.src=SimileAjax.History.historyFile+"?0";
  1331                  *  Position bubble above the target point.
  1008 document.body.appendChild(A);
  1332                  */
  1009 SimileAjax.DOM.registerEvent(A,"load",SimileAjax.History._handleIFrameOnLoad);
  1333 
  1010 SimileAjax.History._iframe=A;
  1334                 var divArrow = createArrow("down");
  1011 }SimileAjax.History._initialized=true;
  1335                 divArrow.style.left = (pageX - halfArrowGraphicWidth - left) + "px";
  1012 };
  1336 
  1013 SimileAjax.History.addListener=function(A){SimileAjax.History.initialize();
  1337                 div.style.left = left + "px";
  1014 SimileAjax.History._listeners.add(A);
  1338                 div.style.top = (pageY - bubbleConfig.arrowGraphicTargetOffset - contentHeight) + "px";
  1015 };
  1339 
  1016 SimileAjax.History.removeListener=function(A){SimileAjax.History.initialize();
  1340                 return;
  1017 SimileAjax.History._listeners.remove(A);
  1341             } else if ((orientation && orientation == "bottom") ||
  1018 };
  1342                 (!orientation &&
  1019 SimileAjax.History.addAction=function(A){SimileAjax.History.initialize();
  1343                     (pageY
  1020 SimileAjax.History._listeners.fire("onBeforePerform",[A]);
  1344                         + bubbleConfig.arrowGraphicTargetOffset
  1021 window.setTimeout(function(){try{A.perform();
  1345                         + contentHeight
  1022 SimileAjax.History._listeners.fire("onAfterPerform",[A]);
  1346                         + bubbleConfig.borderGraphicSize
  1023 if(SimileAjax.History.enabled){SimileAjax.History._actions=SimileAjax.History._actions.slice(0,SimileAjax.History._currentIndex-SimileAjax.History._baseIndex);
  1347                         + bubbleConfig.extraPadding < docHeight))) {
  1024 SimileAjax.History._actions.push(A);
  1348 
  1025 SimileAjax.History._currentIndex++;
  1349                 /*
  1026 var C=SimileAjax.History._actions.length-SimileAjax.History.maxHistoryLength;
  1350                  *  Position bubble below the target point.
  1027 if(C>0){SimileAjax.History._actions=SimileAjax.History._actions.slice(C);
  1351                  */
  1028 SimileAjax.History._baseIndex+=C;
  1352 
  1029 }try{SimileAjax.History._iframe.contentWindow.location.search="?"+SimileAjax.History._currentIndex;
  1353                 var divArrow = createArrow("up");
  1030 }catch(B){var D=SimileAjax.History.formatHistoryEntryTitle(A.label);
  1354                 divArrow.style.left = (pageX - halfArrowGraphicWidth - left) + "px";
  1031 document.title=D;
  1355 
  1032 }}}catch(B){SimileAjax.Debug.exception(B,"Error adding action {"+A.label+"} to history");
  1356                 div.style.left = left + "px";
  1033 }},0);
  1357                 div.style.top = (pageY + bubbleConfig.arrowGraphicTargetOffset) + "px";
  1034 };
  1358 
  1035 SimileAjax.History.addLengthyAction=function(C,A,B){SimileAjax.History.addAction({perform:C,undo:A,label:B,uiLayer:SimileAjax.WindowManager.getBaseLayer(),lengthy:true});
  1359                 return;
  1036 };
  1360             }
  1037 SimileAjax.History._handleIFrameOnLoad=function(){try{var B=SimileAjax.History._iframe.contentWindow.location.search;
  1361         }
  1038 var F=(B.length==0)?0:Math.max(0,parseInt(B.substr(1)));
  1362 
  1039 var E=function(){var G=F-SimileAjax.History._currentIndex;
  1363         var top = pageY - Math.round(contentHeight / 2);
  1040 SimileAjax.History._currentIndex+=G;
  1364         top = pageY < (docHeight / 2) ?
  1041 SimileAjax.History._baseIndex+=G;
  1365             Math.max(top, bubbleConfig.extraPadding + bubbleConfig.borderGraphicSize) :
  1042 SimileAjax.History._iframe.contentWindow.location.search="?"+F;
  1366             Math.min(top, docHeight - bubbleConfig.extraPadding - bubbleConfig.borderGraphicSize - contentHeight);
  1043 };
  1367 
  1044 if(F<SimileAjax.History._currentIndex){SimileAjax.History._listeners.fire("onBeforeUndoSeveral",[]);
  1368         if ((orientation && orientation == "left") ||
  1045 window.setTimeout(function(){while(SimileAjax.History._currentIndex>F&&SimileAjax.History._currentIndex>SimileAjax.History._baseIndex){SimileAjax.History._currentIndex--;
  1369             (!orientation &&
  1046 var G=SimileAjax.History._actions[SimileAjax.History._currentIndex-SimileAjax.History._baseIndex];
  1370                 (pageX
  1047 try{G.undo();
  1371                     - bubbleConfig.arrowGraphicTargetOffset
  1048 }catch(H){SimileAjax.Debug.exception(H,"History: Failed to undo action {"+G.label+"}");
  1372                     - contentWidth
  1049 }}SimileAjax.History._listeners.fire("onAfterUndoSeveral",[]);
  1373                     - bubbleConfig.borderGraphicSize
  1050 E();
  1374                     - bubbleConfig.extraPadding > 0))) {
  1051 },0);
  1375 
  1052 }else{if(F>SimileAjax.History._currentIndex){SimileAjax.History._listeners.fire("onBeforeRedoSeveral",[]);
  1376             /*
  1053 window.setTimeout(function(){while(SimileAjax.History._currentIndex<F&&SimileAjax.History._currentIndex-SimileAjax.History._baseIndex<SimileAjax.History._actions.length){var G=SimileAjax.History._actions[SimileAjax.History._currentIndex-SimileAjax.History._baseIndex];
  1377              *  Position bubble left of the target point.
  1054 try{G.perform();
  1378              */
  1055 }catch(H){SimileAjax.Debug.exception(H,"History: Failed to redo action {"+G.label+"}");
  1379 
  1056 }SimileAjax.History._currentIndex++;
  1380             var divArrow = createArrow("right");
  1057 }SimileAjax.History._listeners.fire("onAfterRedoSeveral",[]);
  1381             divArrow.style.top = (pageY - halfArrowGraphicWidth - top) + "px";
  1058 E();
  1382 
  1059 },0);
  1383             div.style.top = top + "px";
  1060 }else{var A=SimileAjax.History._currentIndex-SimileAjax.History._baseIndex-1;
  1384             div.style.left = (pageX - bubbleConfig.arrowGraphicTargetOffset - contentWidth) + "px";
  1061 var D=(A>=0&&A<SimileAjax.History._actions.length)?SimileAjax.History.formatHistoryEntryTitle(SimileAjax.History._actions[A].label):SimileAjax.History._plainDocumentTitle;
  1385         } else {
  1062 SimileAjax.History._iframe.contentWindow.document.title=D;
  1386 
  1063 document.title=D;
  1387             /*
  1064 }}}catch(C){}};
  1388              *  Position bubble right of the target point, as the last resort.
  1065 SimileAjax.History.getNextUndoAction=function(){try{var A=SimileAjax.History._currentIndex-SimileAjax.History._baseIndex-1;
  1389              */
  1066 return SimileAjax.History._actions[A];
  1390 
  1067 }catch(B){return null;
  1391             var divArrow = createArrow("left");
  1068 }};
  1392             divArrow.style.top = (pageY - halfArrowGraphicWidth - top) + "px";
  1069 SimileAjax.History.getNextRedoAction=function(){try{var A=SimileAjax.History._currentIndex-SimileAjax.History._baseIndex;
  1393 
  1070 return SimileAjax.History._actions[A];
  1394             div.style.top = top + "px";
  1071 }catch(B){return null;
  1395             div.style.left = (pageX + bubbleConfig.arrowGraphicTargetOffset) + "px";
  1072 }};
  1396         }
  1073 
  1397     })();
  1074 
  1398 
  1075 /* html.js */
  1399     document.body.appendChild(div);
  1076 SimileAjax.HTML=new Object();
  1400 
  1077 SimileAjax.HTML._e2uHash={};
  1401     return bubble;
  1078 (function(){var A=SimileAjax.HTML._e2uHash;
  1402 };
  1079 A["nbsp"]="\u00A0[space]";
  1403 
  1080 A["iexcl"]="\u00A1";
  1404 SimileAjax.Graphics.getWindowDimensions = function() {
  1081 A["cent"]="\u00A2";
  1405     if (typeof window.innerHeight == 'number') {
  1082 A["pound"]="\u00A3";
  1406         return { w:window.innerWidth, h:window.innerHeight }; // Non-IE
  1083 A["curren"]="\u00A4";
  1407     } else if (document.documentElement && document.documentElement.clientHeight) {
  1084 A["yen"]="\u00A5";
  1408         return { // IE6+, in "standards compliant mode"
  1085 A["brvbar"]="\u00A6";
  1409             w:document.documentElement.clientWidth,
  1086 A["sect"]="\u00A7";
  1410             h:document.documentElement.clientHeight
  1087 A["uml"]="\u00A8";
  1411         };
  1088 A["copy"]="\u00A9";
  1412     } else if (document.body && document.body.clientHeight) {
  1089 A["ordf"]="\u00AA";
  1413         return { // IE 4 compatible
  1090 A["laquo"]="\u00AB";
  1414             w:document.body.clientWidth,
  1091 A["not"]="\u00AC";
  1415             h:document.body.clientHeight
  1092 A["shy"]="\u00AD";
  1416         };
  1093 A["reg"]="\u00AE";
  1417     }
  1094 A["macr"]="\u00AF";
  1418 };
  1095 A["deg"]="\u00B0";
  1419 
  1096 A["plusmn"]="\u00B1";
  1420 
  1097 A["sup2"]="\u00B2";
  1421 /**
  1098 A["sup3"]="\u00B3";
  1422  * Creates a floating, rounded message bubble in the center of the window for
  1099 A["acute"]="\u00B4";
  1423  * displaying modal information, e.g. "Loading..."
  1100 A["micro"]="\u00B5";
  1424  *
  1101 A["para"]="\u00B6";
  1425  * @param {Document} doc the root document for the page to render on
  1102 A["middot"]="\u00B7";
  1426  * @param {Object} an object with two properties, contentDiv and containerDiv,
  1103 A["cedil"]="\u00B8";
  1427  *   consisting of the newly created DOM elements
  1104 A["sup1"]="\u00B9";
  1428  */
  1105 A["ordm"]="\u00BA";
  1429 SimileAjax.Graphics.createMessageBubble = function(doc) {
  1106 A["raquo"]="\u00BB";
  1430     var containerDiv = doc.createElement("div");
  1107 A["frac14"]="\u00BC";
  1431     if (SimileAjax.Graphics.pngIsTranslucent) {
  1108 A["frac12"]="\u00BD";
  1432         var topDiv = doc.createElement("div");
  1109 A["frac34"]="\u00BE";
  1433         topDiv.style.height = "33px";
  1110 A["iquest"]="\u00BF";
  1434         topDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-top-left.png) top left no-repeat";
  1111 A["Agrave"]="\u00C0";
  1435         topDiv.style.paddingLeft = "44px";
  1112 A["Aacute"]="\u00C1";
  1436         containerDiv.appendChild(topDiv);
  1113 A["Acirc"]="\u00C2";
  1437 
  1114 A["Atilde"]="\u00C3";
  1438         var topRightDiv = doc.createElement("div");
  1115 A["Auml"]="\u00C4";
  1439         topRightDiv.style.height = "33px";
  1116 A["Aring"]="\u00C5";
  1440         topRightDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-top-right.png) top right no-repeat";
  1117 A["AElig"]="\u00C6";
  1441         topDiv.appendChild(topRightDiv);
  1118 A["Ccedil"]="\u00C7";
  1442 
  1119 A["Egrave"]="\u00C8";
  1443         var middleDiv = doc.createElement("div");
  1120 A["Eacute"]="\u00C9";
  1444         middleDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-left.png) top left repeat-y";
  1121 A["Ecirc"]="\u00CA";
  1445         middleDiv.style.paddingLeft = "44px";
  1122 A["Euml"]="\u00CB";
  1446         containerDiv.appendChild(middleDiv);
  1123 A["Igrave"]="\u00CC";
  1447 
  1124 A["Iacute"]="\u00CD";
  1448         var middleRightDiv = doc.createElement("div");
  1125 A["Icirc"]="\u00CE";
  1449         middleRightDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-right.png) top right repeat-y";
  1126 A["Iuml"]="\u00CF";
  1450         middleRightDiv.style.paddingRight = "44px";
  1127 A["ETH"]="\u00D0";
  1451         middleDiv.appendChild(middleRightDiv);
  1128 A["Ntilde"]="\u00D1";
  1452 
  1129 A["Ograve"]="\u00D2";
  1453         var contentDiv = doc.createElement("div");
  1130 A["Oacute"]="\u00D3";
  1454         middleRightDiv.appendChild(contentDiv);
  1131 A["Ocirc"]="\u00D4";
  1455 
  1132 A["Otilde"]="\u00D5";
  1456         var bottomDiv = doc.createElement("div");
  1133 A["Ouml"]="\u00D6";
  1457         bottomDiv.style.height = "55px";
  1134 A["times"]="\u00D7";
  1458         bottomDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-bottom-left.png) bottom left no-repeat";
  1135 A["Oslash"]="\u00D8";
  1459         bottomDiv.style.paddingLeft = "44px";
  1136 A["Ugrave"]="\u00D9";
  1460         containerDiv.appendChild(bottomDiv);
  1137 A["Uacute"]="\u00DA";
  1461 
  1138 A["Ucirc"]="\u00DB";
  1462         var bottomRightDiv = doc.createElement("div");
  1139 A["Uuml"]="\u00DC";
  1463         bottomRightDiv.style.height = "55px";
  1140 A["Yacute"]="\u00DD";
  1464         bottomRightDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-bottom-right.png) bottom right no-repeat";
  1141 A["THORN"]="\u00DE";
  1465         bottomDiv.appendChild(bottomRightDiv);
  1142 A["szlig"]="\u00DF";
  1466     } else {
  1143 A["agrave"]="\u00E0";
  1467         containerDiv.style.border = "2px solid #7777AA";
  1144 A["aacute"]="\u00E1";
  1468         containerDiv.style.padding = "20px";
  1145 A["acirc"]="\u00E2";
  1469         containerDiv.style.background = "white";
  1146 A["atilde"]="\u00E3";
  1470         SimileAjax.Graphics.setOpacity(containerDiv, 90);
  1147 A["auml"]="\u00E4";
  1471 
  1148 A["aring"]="\u00E5";
  1472         var contentDiv = doc.createElement("div");
  1149 A["aelig"]="\u00E6";
  1473         containerDiv.appendChild(contentDiv);
  1150 A["ccedil"]="\u00E7";
  1474     }
  1151 A["egrave"]="\u00E8";
  1475 
  1152 A["eacute"]="\u00E9";
  1476     return {
  1153 A["ecirc"]="\u00EA";
  1477         containerDiv:   containerDiv,
  1154 A["euml"]="\u00EB";
  1478         contentDiv:     contentDiv
  1155 A["igrave"]="\u00EC";
  1479     };
  1156 A["iacute"]="\u00ED";
  1480 };
  1157 A["icirc"]="\u00EE";
  1481 
  1158 A["iuml"]="\u00EF";
  1482 /*==================================================
  1159 A["eth"]="\u00F0";
  1483  *  Animation
  1160 A["ntilde"]="\u00F1";
  1484  *==================================================
  1161 A["ograve"]="\u00F2";
  1485  */
  1162 A["oacute"]="\u00F3";
  1486 
  1163 A["ocirc"]="\u00F4";
  1487 /**
  1164 A["otilde"]="\u00F5";
  1488  * Creates an animation for a function, and an interval of values.  The word
  1165 A["ouml"]="\u00F6";
  1489  * "animation" here is used in the sense of repeatedly calling a function with
  1166 A["divide"]="\u00F7";
  1490  * a current value from within an interval, and a delta value.
  1167 A["oslash"]="\u00F8";
  1491  *
  1168 A["ugrave"]="\u00F9";
  1492  * @param {Function} f a function to be called every 50 milliseconds throughout
  1169 A["uacute"]="\u00FA";
  1493  *   the animation duration, of the form f(current, delta), where current is
  1170 A["ucirc"]="\u00FB";
  1494  *   the current value within the range and delta is the current change.
  1171 A["uuml"]="\u00FC";
  1495  * @param {Number} from a starting value
  1172 A["yacute"]="\u00FD";
  1496  * @param {Number} to an ending value
  1173 A["thorn"]="\u00FE";
  1497  * @param {Number} duration the duration of the animation in milliseconds
  1174 A["yuml"]="\u00FF";
  1498  * @param {Function} [cont] an optional function that is called at the end of
  1175 A["quot"]="\u0022";
  1499  *   the animation, i.e. a continuation.
  1176 A["amp"]="\u0026";
  1500  * @return {SimileAjax.Graphics._Animation} a new animation object
  1177 A["lt"]="\u003C";
  1501  */
  1178 A["gt"]="\u003E";
  1502 SimileAjax.Graphics.createAnimation = function(f, from, to, duration, cont) {
  1179 A["OElig"]="";
  1503     return new SimileAjax.Graphics._Animation(f, from, to, duration, cont);
  1180 A["oelig"]="\u0153";
  1504 };
  1181 A["Scaron"]="\u0160";
  1505 
  1182 A["scaron"]="\u0161";
  1506 SimileAjax.Graphics._Animation = function(f, from, to, duration, cont) {
  1183 A["Yuml"]="\u0178";
  1507     this.f = f;
  1184 A["circ"]="\u02C6";
  1508     this.cont = (typeof cont == "function") ? cont : function() {};
  1185 A["tilde"]="\u02DC";
  1509 
  1186 A["ensp"]="\u2002";
  1510     this.from = from;
  1187 A["emsp"]="\u2003";
  1511     this.to = to;
  1188 A["thinsp"]="\u2009";
  1512     this.current = from;
  1189 A["zwnj"]="\u200C";
  1513 
  1190 A["zwj"]="\u200D";
  1514     this.duration = duration;
  1191 A["lrm"]="\u200E";
  1515     this.start = new Date().getTime();
  1192 A["rlm"]="\u200F";
  1516     this.timePassed = 0;
  1193 A["ndash"]="\u2013";
  1517 };
  1194 A["mdash"]="\u2014";
  1518 
  1195 A["lsquo"]="\u2018";
  1519 /**
  1196 A["rsquo"]="\u2019";
  1520  * Runs this animation.
  1197 A["sbquo"]="\u201A";
  1521  */
  1198 A["ldquo"]="\u201C";
  1522 SimileAjax.Graphics._Animation.prototype.run = function() {
  1199 A["rdquo"]="\u201D";
  1523     var a = this;
  1200 A["bdquo"]="\u201E";
  1524     window.setTimeout(function() { a.step(); }, 50);
  1201 A["dagger"]="\u2020";
  1525 };
  1202 A["Dagger"]="\u2021";
  1526 
  1203 A["permil"]="\u2030";
  1527 /**
  1204 A["lsaquo"]="\u2039";
  1528  * Increments this animation by one step, and then continues the animation with
  1205 A["rsaquo"]="\u203A";
  1529  * <code>run()</code>.
  1206 A["euro"]="\u20AC";
  1530  */
  1207 A["fnof"]="\u0192";
  1531 SimileAjax.Graphics._Animation.prototype.step = function() {
  1208 A["Alpha"]="\u0391";
  1532     this.timePassed += 50;
  1209 A["Beta"]="\u0392";
  1533 
  1210 A["Gamma"]="\u0393";
  1534     var timePassedFraction = this.timePassed / this.duration;
  1211 A["Delta"]="\u0394";
  1535     var parameterFraction = -Math.cos(timePassedFraction * Math.PI) / 2 + 0.5;
  1212 A["Epsilon"]="\u0395";
  1536     var current = parameterFraction * (this.to - this.from) + this.from;
  1213 A["Zeta"]="\u0396";
  1537 
  1214 A["Eta"]="\u0397";
  1538     try {
  1215 A["Theta"]="\u0398";
  1539         this.f(current, current - this.current);
  1216 A["Iota"]="\u0399";
  1540     } catch (e) {
  1217 A["Kappa"]="\u039A";
  1541     }
  1218 A["Lambda"]="\u039B";
  1542     this.current = current;
  1219 A["Mu"]="\u039C";
  1543 
  1220 A["Nu"]="\u039D";
  1544     if (this.timePassed < this.duration) {
  1221 A["Xi"]="\u039E";
  1545         this.run();
  1222 A["Omicron"]="\u039F";
  1546     } else {
  1223 A["Pi"]="\u03A0";
  1547         this.f(this.to, 0);
  1224 A["Rho"]="\u03A1";
  1548         this["cont"]();
  1225 A["Sigma"]="\u03A3";
  1549     }
  1226 A["Tau"]="\u03A4";
  1550 };
  1227 A["Upsilon"]="\u03A5";
  1551 
  1228 A["Phi"]="\u03A6";
  1552 /*==================================================
  1229 A["Chi"]="\u03A7";
  1553  *  CopyPasteButton
  1230 A["Psi"]="\u03A8";
  1554  *
  1231 A["Omega"]="\u03A9";
  1555  *  Adapted from http://spaces.live.com/editorial/rayozzie/demo/liveclip/liveclipsample/techPreview.html.
  1232 A["alpha"]="\u03B1";
  1556  *==================================================
  1233 A["beta"]="\u03B2";
  1557  */
  1234 A["gamma"]="\u03B3";
  1558 
  1235 A["delta"]="\u03B4";
  1559 /**
  1236 A["epsilon"]="\u03B5";
  1560  * Creates a button and textarea for displaying structured data and copying it
  1237 A["zeta"]="\u03B6";
  1561  * to the clipboard.  The data is dynamically generated by the given
  1238 A["eta"]="\u03B7";
  1562  * createDataFunction parameter.
  1239 A["theta"]="\u03B8";
  1563  *
  1240 A["iota"]="\u03B9";
  1564  * @param {String} image an image URL to use as the background for the
  1241 A["kappa"]="\u03BA";
  1565  *   generated box
  1242 A["lambda"]="\u03BB";
  1566  * @param {Number} width the width in pixels of the generated box
  1243 A["mu"]="\u03BC";
  1567  * @param {Number} height the height in pixels of the generated box
  1244 A["nu"]="\u03BD";
  1568  * @param {Function} createDataFunction a function that is called with no
  1245 A["xi"]="\u03BE";
  1569  *   arguments to generate the structured data
  1246 A["omicron"]="\u03BF";
  1570  * @return a new DOM element
  1247 A["pi"]="\u03C0";
  1571  */
  1248 A["rho"]="\u03C1";
  1572 SimileAjax.Graphics.createStructuredDataCopyButton = function(image, width, height, createDataFunction) {
  1249 A["sigmaf"]="\u03C2";
  1573     var div = document.createElement("div");
  1250 A["sigma"]="\u03C3";
  1574     div.style.position = "relative";
  1251 A["tau"]="\u03C4";
  1575     div.style.display = "inline";
  1252 A["upsilon"]="\u03C5";
  1576     div.style.width = width + "px";
  1253 A["phi"]="\u03C6";
  1577     div.style.height = height + "px";
  1254 A["chi"]="\u03C7";
  1578     div.style.overflow = "hidden";
  1255 A["psi"]="\u03C8";
  1579     div.style.margin = "2px";
  1256 A["omega"]="\u03C9";
  1580 
  1257 A["thetasym"]="\u03D1";
  1581     if (SimileAjax.Graphics.pngIsTranslucent) {
  1258 A["upsih"]="\u03D2";
  1582         div.style.background = "url(" + image + ") no-repeat";
  1259 A["piv"]="\u03D6";
  1583     } else {
  1260 A["bull"]="\u2022";
  1584         div.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + image +"', sizingMethod='image')";
  1261 A["hellip"]="\u2026";
  1585     }
  1262 A["prime"]="\u2032";
  1586 
  1263 A["Prime"]="\u2033";
  1587     var style;
  1264 A["oline"]="\u203E";
  1588     if (SimileAjax.Platform.browser.isIE) {
  1265 A["frasl"]="\u2044";
  1589         style = "filter:alpha(opacity=0)";
  1266 A["weierp"]="\u2118";
  1590     } else {
  1267 A["image"]="\u2111";
  1591         style = "opacity: 0";
  1268 A["real"]="\u211C";
  1592     }
  1269 A["trade"]="\u2122";
  1593     div.innerHTML = "<textarea rows='1' autocomplete='off' value='none' style='" + style + "' />";
  1270 A["alefsym"]="\u2135";
  1594 
  1271 A["larr"]="\u2190";
  1595     var textarea = div.firstChild;
  1272 A["uarr"]="\u2191";
  1596     textarea.style.width = width + "px";
  1273 A["rarr"]="\u2192";
  1597     textarea.style.height = height + "px";
  1274 A["darr"]="\u2193";
  1598     textarea.onmousedown = function(evt) {
  1275 A["harr"]="\u2194";
  1599         evt = (evt) ? evt : ((event) ? event : null);
  1276 A["crarr"]="\u21B5";
  1600         if (evt.button == 2) {
  1277 A["lArr"]="\u21D0";
  1601             textarea.value = createDataFunction();
  1278 A["uArr"]="\u21D1";
  1602             textarea.select();
  1279 A["rArr"]="\u21D2";
  1603         }
  1280 A["dArr"]="\u21D3";
  1604     };
  1281 A["hArr"]="\u21D4";
  1605 
  1282 A["forall"]="\u2200";
  1606     return div;
  1283 A["part"]="\u2202";
  1607 };
  1284 A["exist"]="\u2203";
  1608 
  1285 A["empty"]="\u2205";
  1609 /*==================================================
  1286 A["nabla"]="\u2207";
  1610  *  getWidthHeight
  1287 A["isin"]="\u2208";
  1611  *==================================================
  1288 A["notin"]="\u2209";
  1612  */
  1289 A["ni"]="\u220B";
  1613 SimileAjax.Graphics.getWidthHeight = function(el) {
  1290 A["prod"]="\u220F";
  1614     // RETURNS hash {width:  w, height: h} in pixels
  1291 A["sum"]="\u2211";
  1615 
  1292 A["minus"]="\u2212";
  1616     var w, h;
  1293 A["lowast"]="\u2217";
  1617     // offsetWidth rounds on FF, so doesn't work for us.
  1294 A["radic"]="\u221A";
  1618     // See https://bugzilla.mozilla.org/show_bug.cgi?id=458617
  1295 A["prop"]="\u221D";
  1619     if (el.getBoundingClientRect == null) {
  1296 A["infin"]="\u221E";
  1620     	// use offsetWidth
  1297 A["ang"]="\u2220";
  1621       w = el.offsetWidth;
  1298 A["and"]="\u2227";
  1622       h = el.offsetHeight;
  1299 A["or"]="\u2228";
  1623     } else {
  1300 A["cap"]="\u2229";
  1624     	// use getBoundingClientRect
  1301 A["cup"]="\u222A";
  1625       var rect = el.getBoundingClientRect();
  1302 A["int"]="\u222B";
  1626       w = Math.ceil(rect.right - rect.left);
  1303 A["there4"]="\u2234";
  1627     	h = Math.ceil(rect.bottom - rect.top);
  1304 A["sim"]="\u223C";
  1628     }
  1305 A["cong"]="\u2245";
  1629     return {
  1306 A["asymp"]="\u2248";
  1630         width:  w,
  1307 A["ne"]="\u2260";
  1631         height: h
  1308 A["equiv"]="\u2261";
  1632     };
  1309 A["le"]="\u2264";
  1633 };
  1310 A["ge"]="\u2265";
  1634 
  1311 A["sub"]="\u2282";
  1635 
  1312 A["sup"]="\u2283";
  1636 /*==================================================
  1313 A["nsub"]="\u2284";
  1637  *  FontRenderingContext
  1314 A["sube"]="\u2286";
  1638  *==================================================
  1315 A["supe"]="\u2287";
  1639  */
  1316 A["oplus"]="\u2295";
  1640 SimileAjax.Graphics.getFontRenderingContext = function(elmt, width) {
  1317 A["otimes"]="\u2297";
  1641     return new SimileAjax.Graphics._FontRenderingContext(elmt, width);
  1318 A["perp"]="\u22A5";
  1642 };
  1319 A["sdot"]="\u22C5";
  1643 
  1320 A["lceil"]="\u2308";
  1644 SimileAjax.Graphics._FontRenderingContext = function(elmt, width) {
  1321 A["rceil"]="\u2309";
  1645     this._elmt = elmt;
  1322 A["lfloor"]="\u230A";
  1646     this._elmt.style.visibility = "hidden";
  1323 A["rfloor"]="\u230B";
  1647     if (typeof width == "string") {
  1324 A["lang"]="\u2329";
  1648         this._elmt.style.width = width;
  1325 A["rang"]="\u232A";
  1649     } else if (typeof width == "number") {
  1326 A["loz"]="\u25CA";
  1650         this._elmt.style.width = width + "px";
  1327 A["spades"]="\u2660";
  1651     }
  1328 A["clubs"]="\u2663";
  1652 };
  1329 A["hearts"]="\u2665";
  1653 
  1330 A["diams"]="\u2666";
  1654 SimileAjax.Graphics._FontRenderingContext.prototype.dispose = function() {
       
  1655     this._elmt = null;
       
  1656 };
       
  1657 
       
  1658 SimileAjax.Graphics._FontRenderingContext.prototype.update = function() {
       
  1659     this._elmt.innerHTML = "A";
       
  1660     this._lineHeight = this._elmt.offsetHeight;
       
  1661 };
       
  1662 
       
  1663 SimileAjax.Graphics._FontRenderingContext.prototype.computeSize = function(text, className) {
       
  1664     // className arg is optional
       
  1665     var el = this._elmt;
       
  1666     el.innerHTML = text;
       
  1667     el.className = className === undefined ? '' : className;
       
  1668     var wh = SimileAjax.Graphics.getWidthHeight(el);
       
  1669     el.className = ''; // reset for the next guy
       
  1670 
       
  1671     return wh;
       
  1672 };
       
  1673 
       
  1674 SimileAjax.Graphics._FontRenderingContext.prototype.getLineHeight = function() {
       
  1675     return this._lineHeight;
       
  1676 };
       
  1677 
       
  1678 /**
       
  1679  * @fileOverview A collection of date/time utility functions
       
  1680  * @name SimileAjax.DateTime
       
  1681  */
       
  1682 
       
  1683 SimileAjax.DateTime = new Object();
       
  1684 
       
  1685 SimileAjax.DateTime.MILLISECOND    = 0;
       
  1686 SimileAjax.DateTime.SECOND         = 1;
       
  1687 SimileAjax.DateTime.MINUTE         = 2;
       
  1688 SimileAjax.DateTime.HOUR           = 3;
       
  1689 SimileAjax.DateTime.DAY            = 4;
       
  1690 SimileAjax.DateTime.WEEK           = 5;
       
  1691 SimileAjax.DateTime.MONTH          = 6;
       
  1692 SimileAjax.DateTime.YEAR           = 7;
       
  1693 SimileAjax.DateTime.DECADE         = 8;
       
  1694 SimileAjax.DateTime.CENTURY        = 9;
       
  1695 SimileAjax.DateTime.MILLENNIUM     = 10;
       
  1696 
       
  1697 SimileAjax.DateTime.EPOCH          = -1;
       
  1698 SimileAjax.DateTime.ERA            = -2;
       
  1699 
       
  1700 /**
       
  1701  * An array of unit lengths, expressed in milliseconds, of various lengths of
       
  1702  * time.  The array indices are predefined and stored as properties of the
       
  1703  * SimileAjax.DateTime object, e.g. SimileAjax.DateTime.YEAR.
       
  1704  * @type Array
       
  1705  */
       
  1706 SimileAjax.DateTime.gregorianUnitLengths = [];
       
  1707     (function() {
       
  1708         var d = SimileAjax.DateTime;
       
  1709         var a = d.gregorianUnitLengths;
       
  1710 
       
  1711         a[d.MILLISECOND] = 1;
       
  1712         a[d.SECOND]      = 1000;
       
  1713         a[d.MINUTE]      = a[d.SECOND] * 60;
       
  1714         a[d.HOUR]        = a[d.MINUTE] * 60;
       
  1715         a[d.DAY]         = a[d.HOUR] * 24;
       
  1716         a[d.WEEK]        = a[d.DAY] * 7;
       
  1717         a[d.MONTH]       = a[d.DAY] * 31;
       
  1718         a[d.YEAR]        = a[d.DAY] * 365;
       
  1719         a[d.DECADE]      = a[d.YEAR] * 10;
       
  1720         a[d.CENTURY]     = a[d.YEAR] * 100;
       
  1721         a[d.MILLENNIUM]  = a[d.YEAR] * 1000;
       
  1722     })();
       
  1723 
       
  1724 SimileAjax.DateTime._dateRegexp = new RegExp(
       
  1725     "^(-?)([0-9]{4})(" + [
       
  1726         "(-?([0-9]{2})(-?([0-9]{2}))?)", // -month-dayOfMonth
       
  1727         "(-?([0-9]{3}))",                // -dayOfYear
       
  1728         "(-?W([0-9]{2})(-?([1-7]))?)"    // -Wweek-dayOfWeek
       
  1729     ].join("|") + ")?$"
       
  1730 );
       
  1731 SimileAjax.DateTime._timezoneRegexp = new RegExp(
       
  1732     "Z|(([-+])([0-9]{2})(:?([0-9]{2}))?)$"
       
  1733 );
       
  1734 SimileAjax.DateTime._timeRegexp = new RegExp(
       
  1735     "^([0-9]{2})(:?([0-9]{2})(:?([0-9]{2})(\.([0-9]+))?)?)?$"
       
  1736 );
       
  1737 
       
  1738 /**
       
  1739  * Takes a date object and a string containing an ISO 8601 date and sets the
       
  1740  * the date using information parsed from the string.  Note that this method
       
  1741  * does not parse any time information.
       
  1742  *
       
  1743  * @param {Date} dateObject the date object to modify
       
  1744  * @param {String} string an ISO 8601 string to parse
       
  1745  * @return {Date} the modified date object
       
  1746  */
       
  1747 SimileAjax.DateTime.setIso8601Date = function(dateObject, string) {
       
  1748     /*
       
  1749      *  This function has been adapted from dojo.date, v.0.3.0
       
  1750      *  http://dojotoolkit.org/.
       
  1751      */
       
  1752 
       
  1753     var d = string.match(SimileAjax.DateTime._dateRegexp);
       
  1754     if(!d) {
       
  1755         throw new Error("Invalid date string: " + string);
       
  1756     }
       
  1757 
       
  1758     var sign = (d[1] == "-") ? -1 : 1; // BC or AD
       
  1759     var year = sign * d[2];
       
  1760     var month = d[5];
       
  1761     var date = d[7];
       
  1762     var dayofyear = d[9];
       
  1763     var week = d[11];
       
  1764     var dayofweek = (d[13]) ? d[13] : 1;
       
  1765 
       
  1766     dateObject.setUTCFullYear(year);
       
  1767     if (dayofyear) {
       
  1768         dateObject.setUTCMonth(0);
       
  1769         dateObject.setUTCDate(Number(dayofyear));
       
  1770     } else if (week) {
       
  1771         dateObject.setUTCMonth(0);
       
  1772         dateObject.setUTCDate(1);
       
  1773         var gd = dateObject.getUTCDay();
       
  1774         var day =  (gd) ? gd : 7;
       
  1775         var offset = Number(dayofweek) + (7 * Number(week));
       
  1776 
       
  1777         if (day <= 4) {
       
  1778             dateObject.setUTCDate(offset + 1 - day);
       
  1779         } else {
       
  1780             dateObject.setUTCDate(offset + 8 - day);
       
  1781         }
       
  1782     } else {
       
  1783         if (month) {
       
  1784             dateObject.setUTCDate(1);
       
  1785             dateObject.setUTCMonth(month - 1);
       
  1786         }
       
  1787         if (date) {
       
  1788             dateObject.setUTCDate(date);
       
  1789         }
       
  1790     }
       
  1791 
       
  1792     return dateObject;
       
  1793 };
       
  1794 
       
  1795 /**
       
  1796  * Takes a date object and a string containing an ISO 8601 time and sets the
       
  1797  * the time using information parsed from the string.  Note that this method
       
  1798  * does not parse any date information.
       
  1799  *
       
  1800  * @param {Date} dateObject the date object to modify
       
  1801  * @param {String} string an ISO 8601 string to parse
       
  1802  * @return {Date} the modified date object
       
  1803  */
       
  1804 SimileAjax.DateTime.setIso8601Time = function (dateObject, string) {
       
  1805     /*
       
  1806      *  This function has been adapted from dojo.date, v.0.3.0
       
  1807      *  http://dojotoolkit.org/.
       
  1808      */
       
  1809 
       
  1810     var d = string.match(SimileAjax.DateTime._timeRegexp);
       
  1811     if(!d) {
       
  1812         SimileAjax.Debug.warn("Invalid time string: " + string);
       
  1813         return false;
       
  1814     }
       
  1815     var hours = d[1];
       
  1816     var mins = Number((d[3]) ? d[3] : 0);
       
  1817     var secs = (d[5]) ? d[5] : 0;
       
  1818     var ms = d[7] ? (Number("0." + d[7]) * 1000) : 0;
       
  1819 
       
  1820     dateObject.setUTCHours(hours);
       
  1821     dateObject.setUTCMinutes(mins);
       
  1822     dateObject.setUTCSeconds(secs);
       
  1823     dateObject.setUTCMilliseconds(ms);
       
  1824 
       
  1825     return dateObject;
       
  1826 };
       
  1827 
       
  1828 /**
       
  1829  * The timezone offset in minutes in the user's browser.
       
  1830  * @type Number
       
  1831  */
       
  1832 SimileAjax.DateTime.timezoneOffset = new Date().getTimezoneOffset();
       
  1833 
       
  1834 /**
       
  1835  * Takes a date object and a string containing an ISO 8601 date and time and
       
  1836  * sets the date object using information parsed from the string.
       
  1837  *
       
  1838  * @param {Date} dateObject the date object to modify
       
  1839  * @param {String} string an ISO 8601 string to parse
       
  1840  * @return {Date} the modified date object
       
  1841  */
       
  1842 SimileAjax.DateTime.setIso8601 = function (dateObject, string){
       
  1843     /*
       
  1844      *  This function has been adapted from dojo.date, v.0.3.0
       
  1845      *  http://dojotoolkit.org/.
       
  1846      */
       
  1847 
       
  1848     var offset = null;
       
  1849     var comps = (string.indexOf("T") == -1) ? string.split(" ") : string.split("T");
       
  1850 
       
  1851     SimileAjax.DateTime.setIso8601Date(dateObject, comps[0]);
       
  1852     if (comps.length == 2) {
       
  1853         // first strip timezone info from the end
       
  1854         var d = comps[1].match(SimileAjax.DateTime._timezoneRegexp);
       
  1855         if (d) {
       
  1856             if (d[0] == 'Z') {
       
  1857                 offset = 0;
       
  1858             } else {
       
  1859                 offset = (Number(d[3]) * 60) + Number(d[5]);
       
  1860                 offset *= ((d[2] == '-') ? 1 : -1);
       
  1861             }
       
  1862             comps[1] = comps[1].substr(0, comps[1].length - d[0].length);
       
  1863         }
       
  1864 
       
  1865         SimileAjax.DateTime.setIso8601Time(dateObject, comps[1]);
       
  1866     }
       
  1867     if (offset == null) {
       
  1868         offset = dateObject.getTimezoneOffset(); // local time zone if no tz info
       
  1869     }
       
  1870     dateObject.setTime(dateObject.getTime() + offset * 60000);
       
  1871 
       
  1872     return dateObject;
       
  1873 };
       
  1874 
       
  1875 /**
       
  1876  * Takes a string containing an ISO 8601 date and returns a newly instantiated
       
  1877  * date object with the parsed date and time information from the string.
       
  1878  *
       
  1879  * @param {String} string an ISO 8601 string to parse
       
  1880  * @return {Date} a new date object created from the string
       
  1881  */
       
  1882 SimileAjax.DateTime.parseIso8601DateTime = function (string) {
       
  1883     try {
       
  1884         return SimileAjax.DateTime.setIso8601(new Date(0), string);
       
  1885     } catch (e) {
       
  1886         return null;
       
  1887     }
       
  1888 };
       
  1889 
       
  1890 /**
       
  1891  * Takes a string containing a Gregorian date and time and returns a newly
       
  1892  * instantiated date object with the parsed date and time information from the
       
  1893  * string.  If the param is actually an instance of Date instead of a string,
       
  1894  * simply returns the given date instead.
       
  1895  *
       
  1896  * @param {Object} o an object, to either return or parse as a string
       
  1897  * @return {Date} the date object
       
  1898  */
       
  1899 SimileAjax.DateTime.parseGregorianDateTime = function(o) {
       
  1900     if (o == null) {
       
  1901         return null;
       
  1902     } else if (o instanceof Date) {
       
  1903         return o;
       
  1904     }
       
  1905 
       
  1906     var s = o.toString();
       
  1907     if (s.length > 0 && s.length < 8) {
       
  1908         var space = s.indexOf(" ");
       
  1909         if (space > 0) {
       
  1910             var year = parseInt(s.substr(0, space));
       
  1911             var suffix = s.substr(space + 1);
       
  1912             if (suffix.toLowerCase() == "bc") {
       
  1913                 year = 1 - year;
       
  1914             }
       
  1915         } else {
       
  1916             var year = parseInt(s);
       
  1917         }
       
  1918 
       
  1919         var d = new Date(0);
       
  1920         d.setUTCFullYear(year);
       
  1921 
       
  1922         return d;
       
  1923     }
       
  1924 
       
  1925     try {
       
  1926         return new Date(Date.parse(s));
       
  1927     } catch (e) {
       
  1928         return null;
       
  1929     }
       
  1930 };
       
  1931 
       
  1932 /**
       
  1933  * Rounds date objects down to the nearest interval or multiple of an interval.
       
  1934  * This method modifies the given date object, converting it to the given
       
  1935  * timezone if specified.
       
  1936  *
       
  1937  * @param {Date} date the date object to round
       
  1938  * @param {Number} intervalUnit a constant, integer index specifying an
       
  1939  *   interval, e.g. SimileAjax.DateTime.HOUR
       
  1940  * @param {Number} timeZone a timezone shift, given in hours
       
  1941  * @param {Number} multiple a multiple of the interval to round by
       
  1942  * @param {Number} firstDayOfWeek an integer specifying the first day of the
       
  1943  *   week, 0 corresponds to Sunday, 1 to Monday, etc.
       
  1944  */
       
  1945 SimileAjax.DateTime.roundDownToInterval = function(date, intervalUnit, timeZone, multiple, firstDayOfWeek) {
       
  1946     var timeShift = timeZone *
       
  1947         SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR];
       
  1948 
       
  1949     var date2 = new Date(date.getTime() + timeShift);
       
  1950     var clearInDay = function(d) {
       
  1951         d.setUTCMilliseconds(0);
       
  1952         d.setUTCSeconds(0);
       
  1953         d.setUTCMinutes(0);
       
  1954         d.setUTCHours(0);
       
  1955     };
       
  1956     var clearInYear = function(d) {
       
  1957         clearInDay(d);
       
  1958         d.setUTCDate(1);
       
  1959         d.setUTCMonth(0);
       
  1960     };
       
  1961 
       
  1962     switch(intervalUnit) {
       
  1963     case SimileAjax.DateTime.MILLISECOND:
       
  1964         var x = date2.getUTCMilliseconds();
       
  1965         date2.setUTCMilliseconds(x - (x % multiple));
       
  1966         break;
       
  1967     case SimileAjax.DateTime.SECOND:
       
  1968         date2.setUTCMilliseconds(0);
       
  1969 
       
  1970         var x = date2.getUTCSeconds();
       
  1971         date2.setUTCSeconds(x - (x % multiple));
       
  1972         break;
       
  1973     case SimileAjax.DateTime.MINUTE:
       
  1974         date2.setUTCMilliseconds(0);
       
  1975         date2.setUTCSeconds(0);
       
  1976 
       
  1977         var x = date2.getUTCMinutes();
       
  1978         date2.setTime(date2.getTime() -
       
  1979             (x % multiple) * SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.MINUTE]);
       
  1980         break;
       
  1981     case SimileAjax.DateTime.HOUR:
       
  1982         date2.setUTCMilliseconds(0);
       
  1983         date2.setUTCSeconds(0);
       
  1984         date2.setUTCMinutes(0);
       
  1985 
       
  1986         var x = date2.getUTCHours();
       
  1987         date2.setUTCHours(x - (x % multiple));
       
  1988         break;
       
  1989     case SimileAjax.DateTime.DAY:
       
  1990         clearInDay(date2);
       
  1991         break;
       
  1992     case SimileAjax.DateTime.WEEK:
       
  1993         clearInDay(date2);
       
  1994         var d = (date2.getUTCDay() + 7 - firstDayOfWeek) % 7;
       
  1995         date2.setTime(date2.getTime() -
       
  1996             d * SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.DAY]);
       
  1997         break;
       
  1998     case SimileAjax.DateTime.MONTH:
       
  1999         clearInDay(date2);
       
  2000         date2.setUTCDate(1);
       
  2001 
       
  2002         var x = date2.getUTCMonth();
       
  2003         date2.setUTCMonth(x - (x % multiple));
       
  2004         break;
       
  2005     case SimileAjax.DateTime.YEAR:
       
  2006         clearInYear(date2);
       
  2007 
       
  2008         var x = date2.getUTCFullYear();
       
  2009         date2.setUTCFullYear(x - (x % multiple));
       
  2010         break;
       
  2011     case SimileAjax.DateTime.DECADE:
       
  2012         clearInYear(date2);
       
  2013         date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 10) * 10);
       
  2014         break;
       
  2015     case SimileAjax.DateTime.CENTURY:
       
  2016         clearInYear(date2);
       
  2017         date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 100) * 100);
       
  2018         break;
       
  2019     case SimileAjax.DateTime.MILLENNIUM:
       
  2020         clearInYear(date2);
       
  2021         date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 1000) * 1000);
       
  2022         break;
       
  2023     }
       
  2024 
       
  2025     date.setTime(date2.getTime() - timeShift);
       
  2026 };
       
  2027 
       
  2028 /**
       
  2029  * Rounds date objects up to the nearest interval or multiple of an interval.
       
  2030  * This method modifies the given date object, converting it to the given
       
  2031  * timezone if specified.
       
  2032  *
       
  2033  * @param {Date} date the date object to round
       
  2034  * @param {Number} intervalUnit a constant, integer index specifying an
       
  2035  *   interval, e.g. SimileAjax.DateTime.HOUR
       
  2036  * @param {Number} timeZone a timezone shift, given in hours
       
  2037  * @param {Number} multiple a multiple of the interval to round by
       
  2038  * @param {Number} firstDayOfWeek an integer specifying the first day of the
       
  2039  *   week, 0 corresponds to Sunday, 1 to Monday, etc.
       
  2040  * @see SimileAjax.DateTime.roundDownToInterval
       
  2041  */
       
  2042 SimileAjax.DateTime.roundUpToInterval = function(date, intervalUnit, timeZone, multiple, firstDayOfWeek) {
       
  2043     var originalTime = date.getTime();
       
  2044     SimileAjax.DateTime.roundDownToInterval(date, intervalUnit, timeZone, multiple, firstDayOfWeek);
       
  2045     if (date.getTime() < originalTime) {
       
  2046         date.setTime(date.getTime() +
       
  2047             SimileAjax.DateTime.gregorianUnitLengths[intervalUnit] * multiple);
       
  2048     }
       
  2049 };
       
  2050 
       
  2051 /**
       
  2052  * Increments a date object by a specified interval, taking into
       
  2053  * consideration the timezone.
       
  2054  *
       
  2055  * @param {Date} date the date object to increment
       
  2056  * @param {Number} intervalUnit a constant, integer index specifying an
       
  2057  *   interval, e.g. SimileAjax.DateTime.HOUR
       
  2058  * @param {Number} timeZone the timezone offset in hours
       
  2059  */
       
  2060 SimileAjax.DateTime.incrementByInterval = function(date, intervalUnit, timeZone) {
       
  2061     timeZone = (typeof timeZone == 'undefined') ? 0 : timeZone;
       
  2062 
       
  2063     var timeShift = timeZone *
       
  2064         SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR];
       
  2065 
       
  2066     var date2 = new Date(date.getTime() + timeShift);
       
  2067 
       
  2068     switch(intervalUnit) {
       
  2069     case SimileAjax.DateTime.MILLISECOND:
       
  2070         date2.setTime(date2.getTime() + 1)
       
  2071         break;
       
  2072     case SimileAjax.DateTime.SECOND:
       
  2073         date2.setTime(date2.getTime() + 1000);
       
  2074         break;
       
  2075     case SimileAjax.DateTime.MINUTE:
       
  2076         date2.setTime(date2.getTime() +
       
  2077             SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.MINUTE]);
       
  2078         break;
       
  2079     case SimileAjax.DateTime.HOUR:
       
  2080         date2.setTime(date2.getTime() +
       
  2081             SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR]);
       
  2082         break;
       
  2083     case SimileAjax.DateTime.DAY:
       
  2084         date2.setUTCDate(date2.getUTCDate() + 1);
       
  2085         break;
       
  2086     case SimileAjax.DateTime.WEEK:
       
  2087         date2.setUTCDate(date2.getUTCDate() + 7);
       
  2088         break;
       
  2089     case SimileAjax.DateTime.MONTH:
       
  2090         date2.setUTCMonth(date2.getUTCMonth() + 1);
       
  2091         break;
       
  2092     case SimileAjax.DateTime.YEAR:
       
  2093         date2.setUTCFullYear(date2.getUTCFullYear() + 1);
       
  2094         break;
       
  2095     case SimileAjax.DateTime.DECADE:
       
  2096         date2.setUTCFullYear(date2.getUTCFullYear() + 10);
       
  2097         break;
       
  2098     case SimileAjax.DateTime.CENTURY:
       
  2099         date2.setUTCFullYear(date2.getUTCFullYear() + 100);
       
  2100         break;
       
  2101     case SimileAjax.DateTime.MILLENNIUM:
       
  2102         date2.setUTCFullYear(date2.getUTCFullYear() + 1000);
       
  2103         break;
       
  2104     }
       
  2105 
       
  2106     date.setTime(date2.getTime() - timeShift);
       
  2107 };
       
  2108 
       
  2109 /**
       
  2110  * Returns a new date object with the given time offset removed.
       
  2111  *
       
  2112  * @param {Date} date the starting date
       
  2113  * @param {Number} timeZone a timezone specified in an hour offset to remove
       
  2114  * @return {Date} a new date object with the offset removed
       
  2115  */
       
  2116 SimileAjax.DateTime.removeTimeZoneOffset = function(date, timeZone) {
       
  2117     return new Date(date.getTime() +
       
  2118         timeZone * SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR]);
       
  2119 };
       
  2120 
       
  2121 /**
       
  2122  * Returns the timezone of the user's browser.
       
  2123  *
       
  2124  * @return {Number} the timezone in the user's locale in hours
       
  2125  */
       
  2126 SimileAjax.DateTime.getTimezone = function() {
       
  2127     var d = new Date().getTimezoneOffset();
       
  2128     return d / -60;
       
  2129 };
       
  2130 /*==================================================
       
  2131  *  String Utility Functions and Constants
       
  2132  *==================================================
       
  2133  */
       
  2134 
       
  2135 String.prototype.trim = function() {
       
  2136     return this.replace(/^\s+|\s+$/g, '');
       
  2137 };
       
  2138 
       
  2139 String.prototype.startsWith = function(prefix) {
       
  2140     return this.length >= prefix.length && this.substr(0, prefix.length) == prefix;
       
  2141 };
       
  2142 
       
  2143 String.prototype.endsWith = function(suffix) {
       
  2144     return this.length >= suffix.length && this.substr(this.length - suffix.length) == suffix;
       
  2145 };
       
  2146 
       
  2147 String.substitute = function(s, objects) {
       
  2148     var result = "";
       
  2149     var start = 0;
       
  2150     while (start < s.length - 1) {
       
  2151         var percent = s.indexOf("%", start);
       
  2152         if (percent < 0 || percent == s.length - 1) {
       
  2153             break;
       
  2154         } else if (percent > start && s.charAt(percent - 1) == "\\") {
       
  2155             result += s.substring(start, percent - 1) + "%";
       
  2156             start = percent + 1;
       
  2157         } else {
       
  2158             var n = parseInt(s.charAt(percent + 1));
       
  2159             if (isNaN(n) || n >= objects.length) {
       
  2160                 result += s.substring(start, percent + 2);
       
  2161             } else {
       
  2162                 result += s.substring(start, percent) + objects[n].toString();
       
  2163             }
       
  2164             start = percent + 2;
       
  2165         }
       
  2166     }
       
  2167 
       
  2168     if (start < s.length) {
       
  2169         result += s.substring(start);
       
  2170     }
       
  2171     return result;
       
  2172 };
       
  2173 /*==================================================
       
  2174  *  HTML Utility Functions
       
  2175  *==================================================
       
  2176  */
       
  2177 
       
  2178 SimileAjax.HTML = new Object();
       
  2179 
       
  2180 SimileAjax.HTML._e2uHash = {};
       
  2181 (function() {
       
  2182     var e2uHash = SimileAjax.HTML._e2uHash;
       
  2183     e2uHash['nbsp']= '\u00A0[space]';
       
  2184     e2uHash['iexcl']= '\u00A1';
       
  2185     e2uHash['cent']= '\u00A2';
       
  2186     e2uHash['pound']= '\u00A3';
       
  2187     e2uHash['curren']= '\u00A4';
       
  2188     e2uHash['yen']= '\u00A5';
       
  2189     e2uHash['brvbar']= '\u00A6';
       
  2190     e2uHash['sect']= '\u00A7';
       
  2191     e2uHash['uml']= '\u00A8';
       
  2192     e2uHash['copy']= '\u00A9';
       
  2193     e2uHash['ordf']= '\u00AA';
       
  2194     e2uHash['laquo']= '\u00AB';
       
  2195     e2uHash['not']= '\u00AC';
       
  2196     e2uHash['shy']= '\u00AD';
       
  2197     e2uHash['reg']= '\u00AE';
       
  2198     e2uHash['macr']= '\u00AF';
       
  2199     e2uHash['deg']= '\u00B0';
       
  2200     e2uHash['plusmn']= '\u00B1';
       
  2201     e2uHash['sup2']= '\u00B2';
       
  2202     e2uHash['sup3']= '\u00B3';
       
  2203     e2uHash['acute']= '\u00B4';
       
  2204     e2uHash['micro']= '\u00B5';
       
  2205     e2uHash['para']= '\u00B6';
       
  2206     e2uHash['middot']= '\u00B7';
       
  2207     e2uHash['cedil']= '\u00B8';
       
  2208     e2uHash['sup1']= '\u00B9';
       
  2209     e2uHash['ordm']= '\u00BA';
       
  2210     e2uHash['raquo']= '\u00BB';
       
  2211     e2uHash['frac14']= '\u00BC';
       
  2212     e2uHash['frac12']= '\u00BD';
       
  2213     e2uHash['frac34']= '\u00BE';
       
  2214     e2uHash['iquest']= '\u00BF';
       
  2215     e2uHash['Agrave']= '\u00C0';
       
  2216     e2uHash['Aacute']= '\u00C1';
       
  2217     e2uHash['Acirc']= '\u00C2';
       
  2218     e2uHash['Atilde']= '\u00C3';
       
  2219     e2uHash['Auml']= '\u00C4';
       
  2220     e2uHash['Aring']= '\u00C5';
       
  2221     e2uHash['AElig']= '\u00C6';
       
  2222     e2uHash['Ccedil']= '\u00C7';
       
  2223     e2uHash['Egrave']= '\u00C8';
       
  2224     e2uHash['Eacute']= '\u00C9';
       
  2225     e2uHash['Ecirc']= '\u00CA';
       
  2226     e2uHash['Euml']= '\u00CB';
       
  2227     e2uHash['Igrave']= '\u00CC';
       
  2228     e2uHash['Iacute']= '\u00CD';
       
  2229     e2uHash['Icirc']= '\u00CE';
       
  2230     e2uHash['Iuml']= '\u00CF';
       
  2231     e2uHash['ETH']= '\u00D0';
       
  2232     e2uHash['Ntilde']= '\u00D1';
       
  2233     e2uHash['Ograve']= '\u00D2';
       
  2234     e2uHash['Oacute']= '\u00D3';
       
  2235     e2uHash['Ocirc']= '\u00D4';
       
  2236     e2uHash['Otilde']= '\u00D5';
       
  2237     e2uHash['Ouml']= '\u00D6';
       
  2238     e2uHash['times']= '\u00D7';
       
  2239     e2uHash['Oslash']= '\u00D8';
       
  2240     e2uHash['Ugrave']= '\u00D9';
       
  2241     e2uHash['Uacute']= '\u00DA';
       
  2242     e2uHash['Ucirc']= '\u00DB';
       
  2243     e2uHash['Uuml']= '\u00DC';
       
  2244     e2uHash['Yacute']= '\u00DD';
       
  2245     e2uHash['THORN']= '\u00DE';
       
  2246     e2uHash['szlig']= '\u00DF';
       
  2247     e2uHash['agrave']= '\u00E0';
       
  2248     e2uHash['aacute']= '\u00E1';
       
  2249     e2uHash['acirc']= '\u00E2';
       
  2250     e2uHash['atilde']= '\u00E3';
       
  2251     e2uHash['auml']= '\u00E4';
       
  2252     e2uHash['aring']= '\u00E5';
       
  2253     e2uHash['aelig']= '\u00E6';
       
  2254     e2uHash['ccedil']= '\u00E7';
       
  2255     e2uHash['egrave']= '\u00E8';
       
  2256     e2uHash['eacute']= '\u00E9';
       
  2257     e2uHash['ecirc']= '\u00EA';
       
  2258     e2uHash['euml']= '\u00EB';
       
  2259     e2uHash['igrave']= '\u00EC';
       
  2260     e2uHash['iacute']= '\u00ED';
       
  2261     e2uHash['icirc']= '\u00EE';
       
  2262     e2uHash['iuml']= '\u00EF';
       
  2263     e2uHash['eth']= '\u00F0';
       
  2264     e2uHash['ntilde']= '\u00F1';
       
  2265     e2uHash['ograve']= '\u00F2';
       
  2266     e2uHash['oacute']= '\u00F3';
       
  2267     e2uHash['ocirc']= '\u00F4';
       
  2268     e2uHash['otilde']= '\u00F5';
       
  2269     e2uHash['ouml']= '\u00F6';
       
  2270     e2uHash['divide']= '\u00F7';
       
  2271     e2uHash['oslash']= '\u00F8';
       
  2272     e2uHash['ugrave']= '\u00F9';
       
  2273     e2uHash['uacute']= '\u00FA';
       
  2274     e2uHash['ucirc']= '\u00FB';
       
  2275     e2uHash['uuml']= '\u00FC';
       
  2276     e2uHash['yacute']= '\u00FD';
       
  2277     e2uHash['thorn']= '\u00FE';
       
  2278     e2uHash['yuml']= '\u00FF';
       
  2279     e2uHash['quot']= '\u0022';
       
  2280     e2uHash['amp']= '\u0026';
       
  2281     e2uHash['lt']= '\u003C';
       
  2282     e2uHash['gt']= '\u003E';
       
  2283     e2uHash['OElig']= '';
       
  2284     e2uHash['oelig']= '\u0153';
       
  2285     e2uHash['Scaron']= '\u0160';
       
  2286     e2uHash['scaron']= '\u0161';
       
  2287     e2uHash['Yuml']= '\u0178';
       
  2288     e2uHash['circ']= '\u02C6';
       
  2289     e2uHash['tilde']= '\u02DC';
       
  2290     e2uHash['ensp']= '\u2002';
       
  2291     e2uHash['emsp']= '\u2003';
       
  2292     e2uHash['thinsp']= '\u2009';
       
  2293     e2uHash['zwnj']= '\u200C';
       
  2294     e2uHash['zwj']= '\u200D';
       
  2295     e2uHash['lrm']= '\u200E';
       
  2296     e2uHash['rlm']= '\u200F';
       
  2297     e2uHash['ndash']= '\u2013';
       
  2298     e2uHash['mdash']= '\u2014';
       
  2299     e2uHash['lsquo']= '\u2018';
       
  2300     e2uHash['rsquo']= '\u2019';
       
  2301     e2uHash['sbquo']= '\u201A';
       
  2302     e2uHash['ldquo']= '\u201C';
       
  2303     e2uHash['rdquo']= '\u201D';
       
  2304     e2uHash['bdquo']= '\u201E';
       
  2305     e2uHash['dagger']= '\u2020';
       
  2306     e2uHash['Dagger']= '\u2021';
       
  2307     e2uHash['permil']= '\u2030';
       
  2308     e2uHash['lsaquo']= '\u2039';
       
  2309     e2uHash['rsaquo']= '\u203A';
       
  2310     e2uHash['euro']= '\u20AC';
       
  2311     e2uHash['fnof']= '\u0192';
       
  2312     e2uHash['Alpha']= '\u0391';
       
  2313     e2uHash['Beta']= '\u0392';
       
  2314     e2uHash['Gamma']= '\u0393';
       
  2315     e2uHash['Delta']= '\u0394';
       
  2316     e2uHash['Epsilon']= '\u0395';
       
  2317     e2uHash['Zeta']= '\u0396';
       
  2318     e2uHash['Eta']= '\u0397';
       
  2319     e2uHash['Theta']= '\u0398';
       
  2320     e2uHash['Iota']= '\u0399';
       
  2321     e2uHash['Kappa']= '\u039A';
       
  2322     e2uHash['Lambda']= '\u039B';
       
  2323     e2uHash['Mu']= '\u039C';
       
  2324     e2uHash['Nu']= '\u039D';
       
  2325     e2uHash['Xi']= '\u039E';
       
  2326     e2uHash['Omicron']= '\u039F';
       
  2327     e2uHash['Pi']= '\u03A0';
       
  2328     e2uHash['Rho']= '\u03A1';
       
  2329     e2uHash['Sigma']= '\u03A3';
       
  2330     e2uHash['Tau']= '\u03A4';
       
  2331     e2uHash['Upsilon']= '\u03A5';
       
  2332     e2uHash['Phi']= '\u03A6';
       
  2333     e2uHash['Chi']= '\u03A7';
       
  2334     e2uHash['Psi']= '\u03A8';
       
  2335     e2uHash['Omega']= '\u03A9';
       
  2336     e2uHash['alpha']= '\u03B1';
       
  2337     e2uHash['beta']= '\u03B2';
       
  2338     e2uHash['gamma']= '\u03B3';
       
  2339     e2uHash['delta']= '\u03B4';
       
  2340     e2uHash['epsilon']= '\u03B5';
       
  2341     e2uHash['zeta']= '\u03B6';
       
  2342     e2uHash['eta']= '\u03B7';
       
  2343     e2uHash['theta']= '\u03B8';
       
  2344     e2uHash['iota']= '\u03B9';
       
  2345     e2uHash['kappa']= '\u03BA';
       
  2346     e2uHash['lambda']= '\u03BB';
       
  2347     e2uHash['mu']= '\u03BC';
       
  2348     e2uHash['nu']= '\u03BD';
       
  2349     e2uHash['xi']= '\u03BE';
       
  2350     e2uHash['omicron']= '\u03BF';
       
  2351     e2uHash['pi']= '\u03C0';
       
  2352     e2uHash['rho']= '\u03C1';
       
  2353     e2uHash['sigmaf']= '\u03C2';
       
  2354     e2uHash['sigma']= '\u03C3';
       
  2355     e2uHash['tau']= '\u03C4';
       
  2356     e2uHash['upsilon']= '\u03C5';
       
  2357     e2uHash['phi']= '\u03C6';
       
  2358     e2uHash['chi']= '\u03C7';
       
  2359     e2uHash['psi']= '\u03C8';
       
  2360     e2uHash['omega']= '\u03C9';
       
  2361     e2uHash['thetasym']= '\u03D1';
       
  2362     e2uHash['upsih']= '\u03D2';
       
  2363     e2uHash['piv']= '\u03D6';
       
  2364     e2uHash['bull']= '\u2022';
       
  2365     e2uHash['hellip']= '\u2026';
       
  2366     e2uHash['prime']= '\u2032';
       
  2367     e2uHash['Prime']= '\u2033';
       
  2368     e2uHash['oline']= '\u203E';
       
  2369     e2uHash['frasl']= '\u2044';
       
  2370     e2uHash['weierp']= '\u2118';
       
  2371     e2uHash['image']= '\u2111';
       
  2372     e2uHash['real']= '\u211C';
       
  2373     e2uHash['trade']= '\u2122';
       
  2374     e2uHash['alefsym']= '\u2135';
       
  2375     e2uHash['larr']= '\u2190';
       
  2376     e2uHash['uarr']= '\u2191';
       
  2377     e2uHash['rarr']= '\u2192';
       
  2378     e2uHash['darr']= '\u2193';
       
  2379     e2uHash['harr']= '\u2194';
       
  2380     e2uHash['crarr']= '\u21B5';
       
  2381     e2uHash['lArr']= '\u21D0';
       
  2382     e2uHash['uArr']= '\u21D1';
       
  2383     e2uHash['rArr']= '\u21D2';
       
  2384     e2uHash['dArr']= '\u21D3';
       
  2385     e2uHash['hArr']= '\u21D4';
       
  2386     e2uHash['forall']= '\u2200';
       
  2387     e2uHash['part']= '\u2202';
       
  2388     e2uHash['exist']= '\u2203';
       
  2389     e2uHash['empty']= '\u2205';
       
  2390     e2uHash['nabla']= '\u2207';
       
  2391     e2uHash['isin']= '\u2208';
       
  2392     e2uHash['notin']= '\u2209';
       
  2393     e2uHash['ni']= '\u220B';
       
  2394     e2uHash['prod']= '\u220F';
       
  2395     e2uHash['sum']= '\u2211';
       
  2396     e2uHash['minus']= '\u2212';
       
  2397     e2uHash['lowast']= '\u2217';
       
  2398     e2uHash['radic']= '\u221A';
       
  2399     e2uHash['prop']= '\u221D';
       
  2400     e2uHash['infin']= '\u221E';
       
  2401     e2uHash['ang']= '\u2220';
       
  2402     e2uHash['and']= '\u2227';
       
  2403     e2uHash['or']= '\u2228';
       
  2404     e2uHash['cap']= '\u2229';
       
  2405     e2uHash['cup']= '\u222A';
       
  2406     e2uHash['int']= '\u222B';
       
  2407     e2uHash['there4']= '\u2234';
       
  2408     e2uHash['sim']= '\u223C';
       
  2409     e2uHash['cong']= '\u2245';
       
  2410     e2uHash['asymp']= '\u2248';
       
  2411     e2uHash['ne']= '\u2260';
       
  2412     e2uHash['equiv']= '\u2261';
       
  2413     e2uHash['le']= '\u2264';
       
  2414     e2uHash['ge']= '\u2265';
       
  2415     e2uHash['sub']= '\u2282';
       
  2416     e2uHash['sup']= '\u2283';
       
  2417     e2uHash['nsub']= '\u2284';
       
  2418     e2uHash['sube']= '\u2286';
       
  2419     e2uHash['supe']= '\u2287';
       
  2420     e2uHash['oplus']= '\u2295';
       
  2421     e2uHash['otimes']= '\u2297';
       
  2422     e2uHash['perp']= '\u22A5';
       
  2423     e2uHash['sdot']= '\u22C5';
       
  2424     e2uHash['lceil']= '\u2308';
       
  2425     e2uHash['rceil']= '\u2309';
       
  2426     e2uHash['lfloor']= '\u230A';
       
  2427     e2uHash['rfloor']= '\u230B';
       
  2428     e2uHash['lang']= '\u2329';
       
  2429     e2uHash['rang']= '\u232A';
       
  2430     e2uHash['loz']= '\u25CA';
       
  2431     e2uHash['spades']= '\u2660';
       
  2432     e2uHash['clubs']= '\u2663';
       
  2433     e2uHash['hearts']= '\u2665';
       
  2434     e2uHash['diams']= '\u2666';
  1331 })();
  2435 })();
  1332 SimileAjax.HTML.deEntify=function(C){var D=SimileAjax.HTML._e2uHash;
  2436 
  1333 var B=/&(\w+?);/;
  2437 SimileAjax.HTML.deEntify = function(s) {
  1334 while(B.test(C)){var A=C.match(B);
  2438     var e2uHash = SimileAjax.HTML._e2uHash;
  1335 C=C.replace(B,D[A[1]]);
  2439 
  1336 }return C;
  2440     var re = /&(\w+?);/;
  1337 };
  2441     while (re.test(s)) {
  1338 
  2442         var m = s.match(re);
  1339 
  2443         s = s.replace(re, e2uHash[m[1]]);
  1340 /* json.js */
  2444     }
  1341 SimileAjax.JSON=new Object();
  2445     return s;
  1342 (function(){var m={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"};
  2446 };/**
  1343 var s={array:function(x){var a=["["],b,f,i,l=x.length,v;
  2447  * A basic set (in the mathematical sense) data structure
  1344 for(i=0;
  2448  *
  1345 i<l;
  2449  * @constructor
  1346 i+=1){v=x[i];
  2450  * @param {Array or SimileAjax.Set} [a] an initial collection
  1347 f=s[typeof v];
  2451  */
  1348 if(f){v=f(v);
  2452 SimileAjax.Set = function(a) {
  1349 if(typeof v=="string"){if(b){a[a.length]=",";
  2453     this._hash = {};
  1350 }a[a.length]=v;
  2454     this._count = 0;
  1351 b=true;
  2455 
  1352 }}}a[a.length]="]";
  2456     if (a instanceof Array) {
  1353 return a.join("");
  2457         for (var i = 0; i < a.length; i++) {
  1354 },"boolean":function(x){return String(x);
  2458             this.add(a[i]);
  1355 },"null":function(x){return"null";
  2459         }
  1356 },number:function(x){return isFinite(x)?String(x):"null";
  2460     } else if (a instanceof SimileAjax.Set) {
  1357 },object:function(x){if(x){if(x instanceof Array){return s.array(x);
  2461         this.addSet(a);
  1358 }var a=["{"],b,f,i,v;
  2462     }
  1359 for(i in x){v=x[i];
  2463 }
  1360 f=s[typeof v];
  2464 
  1361 if(f){v=f(v);
  2465 /**
  1362 if(typeof v=="string"){if(b){a[a.length]=",";
  2466  * Adds the given object to this set, assuming there it does not already exist
  1363 }a.push(s.string(i),":",v);
  2467  *
  1364 b=true;
  2468  * @param {Object} o the object to add
  1365 }}}a[a.length]="}";
  2469  * @return {Boolean} true if the object was added, false if not
  1366 return a.join("");
  2470  */
  1367 }return"null";
  2471 SimileAjax.Set.prototype.add = function(o) {
  1368 },string:function(x){if(/["\\\x00-\x1f]/.test(x)){x=x.replace(/([\x00-\x1f\\"])/g,function(a,b){var c=m[b];
  2472     if (!(o in this._hash)) {
  1369 if(c){return c;
  2473         this._hash[o] = true;
  1370 }c=b.charCodeAt();
  2474         this._count++;
  1371 return"\\u00"+Math.floor(c/16).toString(16)+(c%16).toString(16);
  2475         return true;
  1372 });
  2476     }
  1373 }return'"'+x+'"';
  2477     return false;
  1374 }};
  2478 }
  1375 SimileAjax.JSON.toJSONString=function(o){if(o instanceof Object){return s.object(o);
  2479 
  1376 }else{if(o instanceof Array){return s.array(o);
  2480 /**
  1377 }else{return o.toString();
  2481  * Adds each element in the given set to this set
  1378 }}};
  2482  *
  1379 SimileAjax.JSON.parseJSON=function(){try{return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(this.replace(/"(\\.|[^"\\])*"/g,"")))&&eval("("+this+")");
  2483  * @param {SimileAjax.Set} set the set of elements to add
  1380 }catch(e){return false;
  2484  */
  1381 }};
  2485 SimileAjax.Set.prototype.addSet = function(set) {
       
  2486     for (var o in set._hash) {
       
  2487         this.add(o);
       
  2488     }
       
  2489 }
       
  2490 
       
  2491 /**
       
  2492  * Removes the given element from this set
       
  2493  *
       
  2494  * @param {Object} o the object to remove
       
  2495  * @return {Boolean} true if the object was successfully removed,
       
  2496  *   false otherwise
       
  2497  */
       
  2498 SimileAjax.Set.prototype.remove = function(o) {
       
  2499     if (o in this._hash) {
       
  2500         delete this._hash[o];
       
  2501         this._count--;
       
  2502         return true;
       
  2503     }
       
  2504     return false;
       
  2505 }
       
  2506 
       
  2507 /**
       
  2508  * Removes the elements in this set that correspond to the elements in the
       
  2509  * given set
       
  2510  *
       
  2511  * @param {SimileAjax.Set} set the set of elements to remove
       
  2512  */
       
  2513 SimileAjax.Set.prototype.removeSet = function(set) {
       
  2514     for (var o in set._hash) {
       
  2515         this.remove(o);
       
  2516     }
       
  2517 }
       
  2518 
       
  2519 /**
       
  2520  * Removes all elements in this set that are not present in the given set, i.e.
       
  2521  * modifies this set to the intersection of the two sets
       
  2522  *
       
  2523  * @param {SimileAjax.Set} set the set to intersect
       
  2524  */
       
  2525 SimileAjax.Set.prototype.retainSet = function(set) {
       
  2526     for (var o in this._hash) {
       
  2527         if (!set.contains(o)) {
       
  2528             delete this._hash[o];
       
  2529             this._count--;
       
  2530         }
       
  2531     }
       
  2532 }
       
  2533 
       
  2534 /**
       
  2535  * Returns whether or not the given element exists in this set
       
  2536  *
       
  2537  * @param {SimileAjax.Set} o the object to test for
       
  2538  * @return {Boolean} true if the object is present, false otherwise
       
  2539  */
       
  2540 SimileAjax.Set.prototype.contains = function(o) {
       
  2541     return (o in this._hash);
       
  2542 }
       
  2543 
       
  2544 /**
       
  2545  * Returns the number of elements in this set
       
  2546  *
       
  2547  * @return {Number} the number of elements in this set
       
  2548  */
       
  2549 SimileAjax.Set.prototype.size = function() {
       
  2550     return this._count;
       
  2551 }
       
  2552 
       
  2553 /**
       
  2554  * Returns the elements of this set as an array
       
  2555  *
       
  2556  * @return {Array} a new array containing the elements of this set
       
  2557  */
       
  2558 SimileAjax.Set.prototype.toArray = function() {
       
  2559     var a = [];
       
  2560     for (var o in this._hash) {
       
  2561         a.push(o);
       
  2562     }
       
  2563     return a;
       
  2564 }
       
  2565 
       
  2566 /**
       
  2567  * Iterates through the elements of this set, order unspecified, executing the
       
  2568  * given function on each element until the function returns true
       
  2569  *
       
  2570  * @param {Function} f a function of form f(element)
       
  2571  */
       
  2572 SimileAjax.Set.prototype.visit = function(f) {
       
  2573     for (var o in this._hash) {
       
  2574         if (f(o) == true) {
       
  2575             break;
       
  2576         }
       
  2577     }
       
  2578 }
       
  2579 
       
  2580 /**
       
  2581  * A sorted array data structure
       
  2582  *
       
  2583  * @constructor
       
  2584  */
       
  2585 SimileAjax.SortedArray = function(compare, initialArray) {
       
  2586     this._a = (initialArray instanceof Array) ? initialArray : [];
       
  2587     this._compare = compare;
       
  2588 };
       
  2589 
       
  2590 SimileAjax.SortedArray.prototype.add = function(elmt) {
       
  2591     var sa = this;
       
  2592     var index = this.find(function(elmt2) {
       
  2593         return sa._compare(elmt2, elmt);
       
  2594     });
       
  2595 
       
  2596     if (index < this._a.length) {
       
  2597         this._a.splice(index, 0, elmt);
       
  2598     } else {
       
  2599         this._a.push(elmt);
       
  2600     }
       
  2601 };
       
  2602 
       
  2603 SimileAjax.SortedArray.prototype.remove = function(elmt) {
       
  2604     var sa = this;
       
  2605     var index = this.find(function(elmt2) {
       
  2606         return sa._compare(elmt2, elmt);
       
  2607     });
       
  2608 
       
  2609     while (index < this._a.length && this._compare(this._a[index], elmt) == 0) {
       
  2610         if (this._a[index] == elmt) {
       
  2611             this._a.splice(index, 1);
       
  2612             return true;
       
  2613         } else {
       
  2614             index++;
       
  2615         }
       
  2616     }
       
  2617     return false;
       
  2618 };
       
  2619 
       
  2620 SimileAjax.SortedArray.prototype.removeAll = function() {
       
  2621     this._a = [];
       
  2622 };
       
  2623 
       
  2624 SimileAjax.SortedArray.prototype.elementAt = function(index) {
       
  2625     return this._a[index];
       
  2626 };
       
  2627 
       
  2628 SimileAjax.SortedArray.prototype.length = function() {
       
  2629     return this._a.length;
       
  2630 };
       
  2631 
       
  2632 SimileAjax.SortedArray.prototype.find = function(compare) {
       
  2633     var a = 0;
       
  2634     var b = this._a.length;
       
  2635 
       
  2636     while (a < b) {
       
  2637         var mid = Math.floor((a + b) / 2);
       
  2638         var c = compare(this._a[mid]);
       
  2639         if (mid == a) {
       
  2640             return c < 0 ? a+1 : a;
       
  2641         } else if (c < 0) {
       
  2642             a = mid;
       
  2643         } else {
       
  2644             b = mid;
       
  2645         }
       
  2646     }
       
  2647     return a;
       
  2648 };
       
  2649 
       
  2650 SimileAjax.SortedArray.prototype.getFirst = function() {
       
  2651     return (this._a.length > 0) ? this._a[0] : null;
       
  2652 };
       
  2653 
       
  2654 SimileAjax.SortedArray.prototype.getLast = function() {
       
  2655     return (this._a.length > 0) ? this._a[this._a.length - 1] : null;
       
  2656 };
       
  2657 
       
  2658 /*==================================================
       
  2659  *  Event Index
       
  2660  *==================================================
       
  2661  */
       
  2662 
       
  2663 SimileAjax.EventIndex = function(unit) {
       
  2664     var eventIndex = this;
       
  2665 
       
  2666     this._unit = (unit != null) ? unit : SimileAjax.NativeDateUnit;
       
  2667     this._events = new SimileAjax.SortedArray(
       
  2668         function(event1, event2) {
       
  2669             return eventIndex._unit.compare(event1.getStart(), event2.getStart());
       
  2670         }
       
  2671     );
       
  2672     this._idToEvent = {};
       
  2673     this._indexed = true;
       
  2674 };
       
  2675 
       
  2676 SimileAjax.EventIndex.prototype.getUnit = function() {
       
  2677     return this._unit;
       
  2678 };
       
  2679 
       
  2680 SimileAjax.EventIndex.prototype.getEvent = function(id) {
       
  2681     return this._idToEvent[id];
       
  2682 };
       
  2683 
       
  2684 SimileAjax.EventIndex.prototype.add = function(evt) {
       
  2685     this._events.add(evt);
       
  2686     this._idToEvent[evt.getID()] = evt;
       
  2687     this._indexed = false;
       
  2688 };
       
  2689 
       
  2690 SimileAjax.EventIndex.prototype.removeAll = function() {
       
  2691     this._events.removeAll();
       
  2692     this._idToEvent = {};
       
  2693     this._indexed = false;
       
  2694 };
       
  2695 
       
  2696 SimileAjax.EventIndex.prototype.getCount = function() {
       
  2697     return this._events.length();
       
  2698 };
       
  2699 
       
  2700 SimileAjax.EventIndex.prototype.getIterator = function(startDate, endDate) {
       
  2701     if (!this._indexed) {
       
  2702         this._index();
       
  2703     }
       
  2704     return new SimileAjax.EventIndex._Iterator(this._events, startDate, endDate, this._unit);
       
  2705 };
       
  2706 
       
  2707 SimileAjax.EventIndex.prototype.getReverseIterator = function(startDate, endDate) {
       
  2708     if (!this._indexed) {
       
  2709         this._index();
       
  2710     }
       
  2711     return new SimileAjax.EventIndex._ReverseIterator(this._events, startDate, endDate, this._unit);
       
  2712 };
       
  2713 
       
  2714 SimileAjax.EventIndex.prototype.getAllIterator = function() {
       
  2715     return new SimileAjax.EventIndex._AllIterator(this._events);
       
  2716 };
       
  2717 
       
  2718 SimileAjax.EventIndex.prototype.getEarliestDate = function() {
       
  2719     var evt = this._events.getFirst();
       
  2720     return (evt == null) ? null : evt.getStart();
       
  2721 };
       
  2722 
       
  2723 SimileAjax.EventIndex.prototype.getLatestDate = function() {
       
  2724     var evt = this._events.getLast();
       
  2725     if (evt == null) {
       
  2726         return null;
       
  2727     }
       
  2728 
       
  2729     if (!this._indexed) {
       
  2730         this._index();
       
  2731     }
       
  2732 
       
  2733     var index = evt._earliestOverlapIndex;
       
  2734     var date = this._events.elementAt(index).getEnd();
       
  2735     for (var i = index + 1; i < this._events.length(); i++) {
       
  2736         date = this._unit.later(date, this._events.elementAt(i).getEnd());
       
  2737     }
       
  2738 
       
  2739     return date;
       
  2740 };
       
  2741 
       
  2742 SimileAjax.EventIndex.prototype._index = function() {
       
  2743     /*
       
  2744      *  For each event, we want to find the earliest preceding
       
  2745      *  event that overlaps with it, if any.
       
  2746      */
       
  2747 
       
  2748     var l = this._events.length();
       
  2749     for (var i = 0; i < l; i++) {
       
  2750         var evt = this._events.elementAt(i);
       
  2751         evt._earliestOverlapIndex = i;
       
  2752     }
       
  2753 
       
  2754     var toIndex = 1;
       
  2755     for (var i = 0; i < l; i++) {
       
  2756         var evt = this._events.elementAt(i);
       
  2757         var end = evt.getEnd();
       
  2758 
       
  2759         toIndex = Math.max(toIndex, i + 1);
       
  2760         while (toIndex < l) {
       
  2761             var evt2 = this._events.elementAt(toIndex);
       
  2762             var start2 = evt2.getStart();
       
  2763 
       
  2764             if (this._unit.compare(start2, end) < 0) {
       
  2765                 evt2._earliestOverlapIndex = i;
       
  2766                 toIndex++;
       
  2767             } else {
       
  2768                 break;
       
  2769             }
       
  2770         }
       
  2771     }
       
  2772     this._indexed = true;
       
  2773 };
       
  2774 
       
  2775 SimileAjax.EventIndex._Iterator = function(events, startDate, endDate, unit) {
       
  2776     this._events = events;
       
  2777     this._startDate = startDate;
       
  2778     this._endDate = endDate;
       
  2779     this._unit = unit;
       
  2780 
       
  2781     this._currentIndex = events.find(function(evt) {
       
  2782         return unit.compare(evt.getStart(), startDate);
       
  2783     });
       
  2784     if (this._currentIndex - 1 >= 0) {
       
  2785         this._currentIndex = this._events.elementAt(this._currentIndex - 1)._earliestOverlapIndex;
       
  2786     }
       
  2787     this._currentIndex--;
       
  2788 
       
  2789     this._maxIndex = events.find(function(evt) {
       
  2790         return unit.compare(evt.getStart(), endDate);
       
  2791     });
       
  2792 
       
  2793     this._hasNext = false;
       
  2794     this._next = null;
       
  2795     this._findNext();
       
  2796 };
       
  2797 
       
  2798 SimileAjax.EventIndex._Iterator.prototype = {
       
  2799     hasNext: function() { return this._hasNext; },
       
  2800     next: function() {
       
  2801         if (this._hasNext) {
       
  2802             var next = this._next;
       
  2803             this._findNext();
       
  2804 
       
  2805             return next;
       
  2806         } else {
       
  2807             return null;
       
  2808         }
       
  2809     },
       
  2810     _findNext: function() {
       
  2811         var unit = this._unit;
       
  2812         while ((++this._currentIndex) < this._maxIndex) {
       
  2813             var evt = this._events.elementAt(this._currentIndex);
       
  2814             if (unit.compare(evt.getStart(), this._endDate) < 0 &&
       
  2815                 unit.compare(evt.getEnd(), this._startDate) > 0) {
       
  2816 
       
  2817                 this._next = evt;
       
  2818                 this._hasNext = true;
       
  2819                 return;
       
  2820             }
       
  2821         }
       
  2822         this._next = null;
       
  2823         this._hasNext = false;
       
  2824     }
       
  2825 };
       
  2826 
       
  2827 SimileAjax.EventIndex._ReverseIterator = function(events, startDate, endDate, unit) {
       
  2828     this._events = events;
       
  2829     this._startDate = startDate;
       
  2830     this._endDate = endDate;
       
  2831     this._unit = unit;
       
  2832 
       
  2833     this._minIndex = events.find(function(evt) {
       
  2834         return unit.compare(evt.getStart(), startDate);
       
  2835     });
       
  2836     if (this._minIndex - 1 >= 0) {
       
  2837         this._minIndex = this._events.elementAt(this._minIndex - 1)._earliestOverlapIndex;
       
  2838     }
       
  2839 
       
  2840     this._maxIndex = events.find(function(evt) {
       
  2841         return unit.compare(evt.getStart(), endDate);
       
  2842     });
       
  2843 
       
  2844     this._currentIndex = this._maxIndex;
       
  2845     this._hasNext = false;
       
  2846     this._next = null;
       
  2847     this._findNext();
       
  2848 };
       
  2849 
       
  2850 SimileAjax.EventIndex._ReverseIterator.prototype = {
       
  2851     hasNext: function() { return this._hasNext; },
       
  2852     next: function() {
       
  2853         if (this._hasNext) {
       
  2854             var next = this._next;
       
  2855             this._findNext();
       
  2856 
       
  2857             return next;
       
  2858         } else {
       
  2859             return null;
       
  2860         }
       
  2861     },
       
  2862     _findNext: function() {
       
  2863         var unit = this._unit;
       
  2864         while ((--this._currentIndex) >= this._minIndex) {
       
  2865             var evt = this._events.elementAt(this._currentIndex);
       
  2866             if (unit.compare(evt.getStart(), this._endDate) < 0 &&
       
  2867                 unit.compare(evt.getEnd(), this._startDate) > 0) {
       
  2868 
       
  2869                 this._next = evt;
       
  2870                 this._hasNext = true;
       
  2871                 return;
       
  2872             }
       
  2873         }
       
  2874         this._next = null;
       
  2875         this._hasNext = false;
       
  2876     }
       
  2877 };
       
  2878 
       
  2879 SimileAjax.EventIndex._AllIterator = function(events) {
       
  2880     this._events = events;
       
  2881     this._index = 0;
       
  2882 };
       
  2883 
       
  2884 SimileAjax.EventIndex._AllIterator.prototype = {
       
  2885     hasNext: function() {
       
  2886         return this._index < this._events.length();
       
  2887     },
       
  2888     next: function() {
       
  2889         return this._index < this._events.length() ?
       
  2890             this._events.elementAt(this._index++) : null;
       
  2891     }
       
  2892 };/*==================================================
       
  2893  *  Default Unit
       
  2894  *==================================================
       
  2895  */
       
  2896 
       
  2897 SimileAjax.NativeDateUnit = new Object();
       
  2898 
       
  2899 SimileAjax.NativeDateUnit.makeDefaultValue = function() {
       
  2900     return new Date();
       
  2901 };
       
  2902 
       
  2903 SimileAjax.NativeDateUnit.cloneValue = function(v) {
       
  2904     return new Date(v.getTime());
       
  2905 };
       
  2906 
       
  2907 SimileAjax.NativeDateUnit.getParser = function(format) {
       
  2908     if (typeof format == "string") {
       
  2909         format = format.toLowerCase();
       
  2910     }
       
  2911     return (format == "iso8601" || format == "iso 8601") ?
       
  2912         SimileAjax.DateTime.parseIso8601DateTime : 
       
  2913         SimileAjax.DateTime.parseGregorianDateTime;
       
  2914 };
       
  2915 
       
  2916 SimileAjax.NativeDateUnit.parseFromObject = function(o) {
       
  2917     return SimileAjax.DateTime.parseGregorianDateTime(o);
       
  2918 };
       
  2919 
       
  2920 SimileAjax.NativeDateUnit.toNumber = function(v) {
       
  2921     return v.getTime();
       
  2922 };
       
  2923 
       
  2924 SimileAjax.NativeDateUnit.fromNumber = function(n) {
       
  2925     return new Date(n);
       
  2926 };
       
  2927 
       
  2928 SimileAjax.NativeDateUnit.compare = function(v1, v2) {
       
  2929     var n1, n2;
       
  2930     if (typeof v1 == "object") {
       
  2931         n1 = v1.getTime();
       
  2932     } else {
       
  2933         n1 = Number(v1);
       
  2934     }
       
  2935     if (typeof v2 == "object") {
       
  2936         n2 = v2.getTime();
       
  2937     } else {
       
  2938         n2 = Number(v2);
       
  2939     }
       
  2940     
       
  2941     return n1 - n2;
       
  2942 };
       
  2943 
       
  2944 SimileAjax.NativeDateUnit.earlier = function(v1, v2) {
       
  2945     return SimileAjax.NativeDateUnit.compare(v1, v2) < 0 ? v1 : v2;
       
  2946 };
       
  2947 
       
  2948 SimileAjax.NativeDateUnit.later = function(v1, v2) {
       
  2949     return SimileAjax.NativeDateUnit.compare(v1, v2) > 0 ? v1 : v2;
       
  2950 };
       
  2951 
       
  2952 SimileAjax.NativeDateUnit.change = function(v, n) {
       
  2953     return new Date(v.getTime() + n);
       
  2954 };
       
  2955 
       
  2956 /*==================================================
       
  2957  *  General, miscellaneous SimileAjax stuff
       
  2958  *==================================================
       
  2959  */
       
  2960 
       
  2961 SimileAjax.ListenerQueue = function(wildcardHandlerName) {
       
  2962     this._listeners = [];
       
  2963     this._wildcardHandlerName = wildcardHandlerName;
       
  2964 };
       
  2965 
       
  2966 SimileAjax.ListenerQueue.prototype.add = function(listener) {
       
  2967     this._listeners.push(listener);
       
  2968 };
       
  2969 
       
  2970 SimileAjax.ListenerQueue.prototype.remove = function(listener) {
       
  2971     var listeners = this._listeners;
       
  2972     for (var i = 0; i < listeners.length; i++) {
       
  2973         if (listeners[i] == listener) {
       
  2974             listeners.splice(i, 1);
       
  2975             break;
       
  2976         }
       
  2977     }
       
  2978 };
       
  2979 
       
  2980 SimileAjax.ListenerQueue.prototype.fire = function(handlerName, args) {
       
  2981     var listeners = [].concat(this._listeners);
       
  2982     for (var i = 0; i < listeners.length; i++) {
       
  2983         var listener = listeners[i];
       
  2984         if (handlerName in listener) {
       
  2985             try {
       
  2986                 listener[handlerName].apply(listener, args);
       
  2987             } catch (e) {
       
  2988                 SimileAjax.Debug.exception("Error firing event of name " + handlerName, e);
       
  2989             }
       
  2990         } else if (this._wildcardHandlerName != null &&
       
  2991             this._wildcardHandlerName in listener) {
       
  2992             try {
       
  2993                 listener[this._wildcardHandlerName].apply(listener, [ handlerName ]);
       
  2994             } catch (e) {
       
  2995                 SimileAjax.Debug.exception("Error firing event of name " + handlerName + " to wildcard handler", e);
       
  2996             }
       
  2997         }
       
  2998     }
       
  2999 };
       
  3000 
       
  3001 /*======================================================================
       
  3002  *  History
       
  3003  *
       
  3004  *  This is a singleton that keeps track of undoable user actions and
       
  3005  *  performs undos and redos in response to the browser's Back and
       
  3006  *  Forward buttons.
       
  3007  *
       
  3008  *  Call addAction(action) to register an undoable user action. action
       
  3009  *  must have 4 fields:
       
  3010  *
       
  3011  *      perform: an argument-less function that carries out the action
       
  3012  *      undo:    an argument-less function that undos the action
       
  3013  *      label:   a short, user-friendly string describing the action
       
  3014  *      uiLayer: the UI layer on which the action takes place
       
  3015  *
       
  3016  *  By default, the history keeps track of upto 10 actions. You can
       
  3017  *  configure this behavior by setting
       
  3018  *      SimileAjax.History.maxHistoryLength
       
  3019  *  to a different number.
       
  3020  *
       
  3021  *  An iframe is inserted into the document's body element to track
       
  3022  *  onload events.
       
  3023  *======================================================================
       
  3024  */
       
  3025 
       
  3026 SimileAjax.History = {
       
  3027     maxHistoryLength:       10,
       
  3028     historyFile:            "__history__.html",
       
  3029     enabled:               true,
       
  3030 
       
  3031     _initialized:           false,
       
  3032     _listeners:             new SimileAjax.ListenerQueue(),
       
  3033 
       
  3034     _actions:               [],
       
  3035     _baseIndex:             0,
       
  3036     _currentIndex:          0,
       
  3037 
       
  3038     _plainDocumentTitle:    document.title
       
  3039 };
       
  3040 
       
  3041 SimileAjax.History.formatHistoryEntryTitle = function(actionLabel) {
       
  3042     return SimileAjax.History._plainDocumentTitle + " {" + actionLabel + "}";
       
  3043 };
       
  3044 
       
  3045 SimileAjax.History.initialize = function() {
       
  3046     if (SimileAjax.History._initialized) {
       
  3047         return;
       
  3048     }
       
  3049 
       
  3050     if (SimileAjax.History.enabled) {
       
  3051         var iframe = document.createElement("iframe");
       
  3052         iframe.id = "simile-ajax-history";
       
  3053         iframe.style.position = "absolute";
       
  3054         iframe.style.width = "10px";
       
  3055         iframe.style.height = "10px";
       
  3056         iframe.style.top = "0px";
       
  3057         iframe.style.left = "0px";
       
  3058         iframe.style.visibility = "hidden";
       
  3059         iframe.src = SimileAjax.History.historyFile + "?0";
       
  3060 
       
  3061         document.body.appendChild(iframe);
       
  3062         SimileAjax.DOM.registerEvent(iframe, "load", SimileAjax.History._handleIFrameOnLoad);
       
  3063 
       
  3064         SimileAjax.History._iframe = iframe;
       
  3065     }
       
  3066     SimileAjax.History._initialized = true;
       
  3067 };
       
  3068 
       
  3069 SimileAjax.History.addListener = function(listener) {
       
  3070     SimileAjax.History.initialize();
       
  3071 
       
  3072     SimileAjax.History._listeners.add(listener);
       
  3073 };
       
  3074 
       
  3075 SimileAjax.History.removeListener = function(listener) {
       
  3076     SimileAjax.History.initialize();
       
  3077 
       
  3078     SimileAjax.History._listeners.remove(listener);
       
  3079 };
       
  3080 
       
  3081 SimileAjax.History.addAction = function(action) {
       
  3082     SimileAjax.History.initialize();
       
  3083 
       
  3084     SimileAjax.History._listeners.fire("onBeforePerform", [ action ]);
       
  3085     window.setTimeout(function() {
       
  3086         try {
       
  3087             action.perform();
       
  3088             SimileAjax.History._listeners.fire("onAfterPerform", [ action ]);
       
  3089 
       
  3090             if (SimileAjax.History.enabled) {
       
  3091                 SimileAjax.History._actions = SimileAjax.History._actions.slice(
       
  3092                     0, SimileAjax.History._currentIndex - SimileAjax.History._baseIndex);
       
  3093 
       
  3094                 SimileAjax.History._actions.push(action);
       
  3095                 SimileAjax.History._currentIndex++;
       
  3096 
       
  3097                 var diff = SimileAjax.History._actions.length - SimileAjax.History.maxHistoryLength;
       
  3098                 if (diff > 0) {
       
  3099                     SimileAjax.History._actions = SimileAjax.History._actions.slice(diff);
       
  3100                     SimileAjax.History._baseIndex += diff;
       
  3101                 }
       
  3102 
       
  3103                 try {
       
  3104                     SimileAjax.History._iframe.contentWindow.location.search =
       
  3105                         "?" + SimileAjax.History._currentIndex;
       
  3106                 } catch (e) {
       
  3107                     /*
       
  3108                      *  We can't modify location.search most probably because it's a file:// url.
       
  3109                      *  We'll just going to modify the document's title.
       
  3110                      */
       
  3111                     var title = SimileAjax.History.formatHistoryEntryTitle(action.label);
       
  3112                     document.title = title;
       
  3113                 }
       
  3114             }
       
  3115         } catch (e) {
       
  3116             SimileAjax.Debug.exception(e, "Error adding action {" + action.label + "} to history");
       
  3117         }
       
  3118     }, 0);
       
  3119 };
       
  3120 
       
  3121 SimileAjax.History.addLengthyAction = function(perform, undo, label) {
       
  3122     SimileAjax.History.addAction({
       
  3123         perform:    perform,
       
  3124         undo:       undo,
       
  3125         label:      label,
       
  3126         uiLayer:    SimileAjax.WindowManager.getBaseLayer(),
       
  3127         lengthy:    true
       
  3128     });
       
  3129 };
       
  3130 
       
  3131 SimileAjax.History._handleIFrameOnLoad = function() {
       
  3132     /*
       
  3133      *  This function is invoked when the user herself
       
  3134      *  navigates backward or forward. We need to adjust
       
  3135      *  the application's state accordingly.
       
  3136      */
       
  3137 
       
  3138     try {
       
  3139         var q = SimileAjax.History._iframe.contentWindow.location.search;
       
  3140         var c = (q.length == 0) ? 0 : Math.max(0, parseInt(q.substr(1)));
       
  3141 
       
  3142         var finishUp = function() {
       
  3143             var diff = c - SimileAjax.History._currentIndex;
       
  3144             SimileAjax.History._currentIndex += diff;
       
  3145             SimileAjax.History._baseIndex += diff;
       
  3146 
       
  3147             SimileAjax.History._iframe.contentWindow.location.search = "?" + c;
       
  3148         };
       
  3149 
       
  3150         if (c < SimileAjax.History._currentIndex) { // need to undo
       
  3151             SimileAjax.History._listeners.fire("onBeforeUndoSeveral", []);
       
  3152             window.setTimeout(function() {
       
  3153                 while (SimileAjax.History._currentIndex > c &&
       
  3154                        SimileAjax.History._currentIndex > SimileAjax.History._baseIndex) {
       
  3155 
       
  3156                     SimileAjax.History._currentIndex--;
       
  3157 
       
  3158                     var action = SimileAjax.History._actions[SimileAjax.History._currentIndex - SimileAjax.History._baseIndex];
       
  3159 
       
  3160                     try {
       
  3161                         action.undo();
       
  3162                     } catch (e) {
       
  3163                         SimileAjax.Debug.exception(e, "History: Failed to undo action {" + action.label + "}");
       
  3164                     }
       
  3165                 }
       
  3166 
       
  3167                 SimileAjax.History._listeners.fire("onAfterUndoSeveral", []);
       
  3168                 finishUp();
       
  3169             }, 0);
       
  3170         } else if (c > SimileAjax.History._currentIndex) { // need to redo
       
  3171             SimileAjax.History._listeners.fire("onBeforeRedoSeveral", []);
       
  3172             window.setTimeout(function() {
       
  3173                 while (SimileAjax.History._currentIndex < c &&
       
  3174                        SimileAjax.History._currentIndex - SimileAjax.History._baseIndex < SimileAjax.History._actions.length) {
       
  3175 
       
  3176                     var action = SimileAjax.History._actions[SimileAjax.History._currentIndex - SimileAjax.History._baseIndex];
       
  3177 
       
  3178                     try {
       
  3179                         action.perform();
       
  3180                     } catch (e) {
       
  3181                         SimileAjax.Debug.exception(e, "History: Failed to redo action {" + action.label + "}");
       
  3182                     }
       
  3183 
       
  3184                     SimileAjax.History._currentIndex++;
       
  3185                 }
       
  3186 
       
  3187                 SimileAjax.History._listeners.fire("onAfterRedoSeveral", []);
       
  3188                 finishUp();
       
  3189             }, 0);
       
  3190         } else {
       
  3191             var index = SimileAjax.History._currentIndex - SimileAjax.History._baseIndex - 1;
       
  3192             var title = (index >= 0 && index < SimileAjax.History._actions.length) ?
       
  3193                 SimileAjax.History.formatHistoryEntryTitle(SimileAjax.History._actions[index].label) :
       
  3194                 SimileAjax.History._plainDocumentTitle;
       
  3195 
       
  3196             SimileAjax.History._iframe.contentWindow.document.title = title;
       
  3197             document.title = title;
       
  3198         }
       
  3199     } catch (e) {
       
  3200         // silent
       
  3201     }
       
  3202 };
       
  3203 
       
  3204 SimileAjax.History.getNextUndoAction = function() {
       
  3205     try {
       
  3206         var index = SimileAjax.History._currentIndex - SimileAjax.History._baseIndex - 1;
       
  3207         return SimileAjax.History._actions[index];
       
  3208     } catch (e) {
       
  3209         return null;
       
  3210     }
       
  3211 };
       
  3212 
       
  3213 SimileAjax.History.getNextRedoAction = function() {
       
  3214     try {
       
  3215         var index = SimileAjax.History._currentIndex - SimileAjax.History._baseIndex;
       
  3216         return SimileAjax.History._actions[index];
       
  3217     } catch (e) {
       
  3218         return null;
       
  3219     }
       
  3220 };
       
  3221 /**
       
  3222  * @fileOverview UI layers and window-wide dragging
       
  3223  * @name SimileAjax.WindowManager
       
  3224  */
       
  3225 
       
  3226 /**
       
  3227  *  This is a singleton that keeps track of UI layers (modal and
       
  3228  *  modeless) and enables/disables UI elements based on which layers
       
  3229  *  they belong to. It also provides window-wide dragging
       
  3230  *  implementation.
       
  3231  */
       
  3232 SimileAjax.WindowManager = {
       
  3233     _initialized:       false,
       
  3234     _listeners:         [],
       
  3235 
       
  3236     _draggedElement:                null,
       
  3237     _draggedElementCallback:        null,
       
  3238     _dropTargetHighlightElement:    null,
       
  3239     _lastCoords:                    null,
       
  3240     _ghostCoords:                   null,
       
  3241     _draggingMode:                  "",
       
  3242     _dragging:                      false,
       
  3243 
       
  3244     _layers:            []
       
  3245 };
       
  3246 
       
  3247 SimileAjax.WindowManager.initialize = function() {
       
  3248     if (SimileAjax.WindowManager._initialized) {
       
  3249         return;
       
  3250     }
       
  3251 
       
  3252     SimileAjax.DOM.registerEvent(document.body, "mousedown", SimileAjax.WindowManager._onBodyMouseDown);
       
  3253     SimileAjax.DOM.registerEvent(document.body, "mousemove", SimileAjax.WindowManager._onBodyMouseMove);
       
  3254     SimileAjax.DOM.registerEvent(document.body, "mouseup",   SimileAjax.WindowManager._onBodyMouseUp);
       
  3255     SimileAjax.DOM.registerEvent(document, "keydown",       SimileAjax.WindowManager._onBodyKeyDown);
       
  3256     SimileAjax.DOM.registerEvent(document, "keyup",         SimileAjax.WindowManager._onBodyKeyUp);
       
  3257 
       
  3258     SimileAjax.WindowManager._layers.push({index: 0});
       
  3259 
       
  3260     SimileAjax.WindowManager._historyListener = {
       
  3261         onBeforeUndoSeveral:    function() {},
       
  3262         onAfterUndoSeveral:     function() {},
       
  3263         onBeforeUndo:           function() {},
       
  3264         onAfterUndo:            function() {},
       
  3265 
       
  3266         onBeforeRedoSeveral:    function() {},
       
  3267         onAfterRedoSeveral:     function() {},
       
  3268         onBeforeRedo:           function() {},
       
  3269         onAfterRedo:            function() {}
       
  3270     };
       
  3271     SimileAjax.History.addListener(SimileAjax.WindowManager._historyListener);
       
  3272 
       
  3273     SimileAjax.WindowManager._initialized = true;
       
  3274 };
       
  3275 
       
  3276 SimileAjax.WindowManager.getBaseLayer = function() {
       
  3277     SimileAjax.WindowManager.initialize();
       
  3278     return SimileAjax.WindowManager._layers[0];
       
  3279 };
       
  3280 
       
  3281 SimileAjax.WindowManager.getHighestLayer = function() {
       
  3282     SimileAjax.WindowManager.initialize();
       
  3283     return SimileAjax.WindowManager._layers[SimileAjax.WindowManager._layers.length - 1];
       
  3284 };
       
  3285 
       
  3286 SimileAjax.WindowManager.registerEventWithObject = function(elmt, eventName, obj, handlerName, layer) {
       
  3287     SimileAjax.WindowManager.registerEvent(
       
  3288         elmt,
       
  3289         eventName,
       
  3290         function(elmt2, evt, target) {
       
  3291             return obj[handlerName].call(obj, elmt2, evt, target);
       
  3292         },
       
  3293         layer
       
  3294     );
       
  3295 };
       
  3296 
       
  3297 SimileAjax.WindowManager.registerEvent = function(elmt, eventName, handler, layer) {
       
  3298     if (layer == null) {
       
  3299         layer = SimileAjax.WindowManager.getHighestLayer();
       
  3300     }
       
  3301 
       
  3302     var handler2 = function(elmt, evt, target) {
       
  3303         if (SimileAjax.WindowManager._canProcessEventAtLayer(layer)) {
       
  3304             SimileAjax.WindowManager._popToLayer(layer.index);
       
  3305             try {
       
  3306                 handler(elmt, evt, target);
       
  3307             } catch (e) {
       
  3308                 SimileAjax.Debug.exception(e);
       
  3309             }
       
  3310         }
       
  3311         SimileAjax.DOM.cancelEvent(evt);
       
  3312         return false;
       
  3313     }
       
  3314 
       
  3315     SimileAjax.DOM.registerEvent(elmt, eventName, handler2);
       
  3316 };
       
  3317 
       
  3318 SimileAjax.WindowManager.pushLayer = function(f, ephemeral, elmt) {
       
  3319     var layer = { onPop: f, index: SimileAjax.WindowManager._layers.length, ephemeral: (ephemeral), elmt: elmt };
       
  3320     SimileAjax.WindowManager._layers.push(layer);
       
  3321 
       
  3322     return layer;
       
  3323 };
       
  3324 
       
  3325 SimileAjax.WindowManager.popLayer = function(layer) {
       
  3326     for (var i = 1; i < SimileAjax.WindowManager._layers.length; i++) {
       
  3327         if (SimileAjax.WindowManager._layers[i] == layer) {
       
  3328             SimileAjax.WindowManager._popToLayer(i - 1);
       
  3329             break;
       
  3330         }
       
  3331     }
       
  3332 };
       
  3333 
       
  3334 SimileAjax.WindowManager.popAllLayers = function() {
       
  3335     SimileAjax.WindowManager._popToLayer(0);
       
  3336 };
       
  3337 
       
  3338 SimileAjax.WindowManager.registerForDragging = function(elmt, callback, layer) {
       
  3339     SimileAjax.WindowManager.registerEvent(
       
  3340         elmt,
       
  3341         "mousedown",
       
  3342         function(elmt, evt, target) {
       
  3343             SimileAjax.WindowManager._handleMouseDown(elmt, evt, callback);
       
  3344         },
       
  3345         layer
       
  3346     );
       
  3347 };
       
  3348 
       
  3349 SimileAjax.WindowManager._popToLayer = function(level) {
       
  3350     while (level+1 < SimileAjax.WindowManager._layers.length) {
       
  3351         try {
       
  3352             var layer = SimileAjax.WindowManager._layers.pop();
       
  3353             if (layer.onPop != null) {
       
  3354                 layer.onPop();
       
  3355             }
       
  3356         } catch (e) {
       
  3357         }
       
  3358     }
       
  3359 };
       
  3360 
       
  3361 SimileAjax.WindowManager._canProcessEventAtLayer = function(layer) {
       
  3362     if (layer.index == (SimileAjax.WindowManager._layers.length - 1)) {
       
  3363         return true;
       
  3364     }
       
  3365     for (var i = layer.index + 1; i < SimileAjax.WindowManager._layers.length; i++) {
       
  3366         if (!SimileAjax.WindowManager._layers[i].ephemeral) {
       
  3367             return false;
       
  3368         }
       
  3369     }
       
  3370     return true;
       
  3371 };
       
  3372 
       
  3373 SimileAjax.WindowManager.cancelPopups = function(evt) {
       
  3374     var evtCoords = (evt) ? SimileAjax.DOM.getEventPageCoordinates(evt) : { x: -1, y: -1 };
       
  3375 
       
  3376     var i = SimileAjax.WindowManager._layers.length - 1;
       
  3377     while (i > 0 && SimileAjax.WindowManager._layers[i].ephemeral) {
       
  3378         var layer = SimileAjax.WindowManager._layers[i];
       
  3379         if (layer.elmt != null) { // if event falls within main element of layer then don't cancel
       
  3380             var elmt = layer.elmt;
       
  3381             var elmtCoords = SimileAjax.DOM.getPageCoordinates(elmt);
       
  3382             if (evtCoords.x >= elmtCoords.left && evtCoords.x < (elmtCoords.left + elmt.offsetWidth) &&
       
  3383                 evtCoords.y >= elmtCoords.top && evtCoords.y < (elmtCoords.top + elmt.offsetHeight)) {
       
  3384                 break;
       
  3385             }
       
  3386         }
       
  3387         i--;
       
  3388     }
       
  3389     SimileAjax.WindowManager._popToLayer(i);
       
  3390 };
       
  3391 
       
  3392 SimileAjax.WindowManager._onBodyMouseDown = function(elmt, evt, target) {
       
  3393     if (!("eventPhase" in evt) || evt.eventPhase == evt.BUBBLING_PHASE) {
       
  3394         SimileAjax.WindowManager.cancelPopups(evt);
       
  3395     }
       
  3396 };
       
  3397 
       
  3398 SimileAjax.WindowManager._handleMouseDown = function(elmt, evt, callback) {
       
  3399     SimileAjax.WindowManager._draggedElement = elmt;
       
  3400     SimileAjax.WindowManager._draggedElementCallback = callback;
       
  3401     SimileAjax.WindowManager._lastCoords = { x: evt.clientX, y: evt.clientY };
       
  3402 
       
  3403     SimileAjax.DOM.cancelEvent(evt);
       
  3404     return false;
       
  3405 };
       
  3406 
       
  3407 SimileAjax.WindowManager._onBodyKeyDown = function(elmt, evt, target) {
       
  3408     if (SimileAjax.WindowManager._dragging) {
       
  3409         if (evt.keyCode == 27) { // esc
       
  3410             SimileAjax.WindowManager._cancelDragging();
       
  3411         } else if ((evt.keyCode == 17 || evt.keyCode == 16) && SimileAjax.WindowManager._draggingMode != "copy") {
       
  3412             SimileAjax.WindowManager._draggingMode = "copy";
       
  3413 
       
  3414             var img = SimileAjax.Graphics.createTranslucentImage(SimileAjax.urlPrefix + "images/copy.png");
       
  3415             img.style.position = "absolute";
       
  3416             img.style.left = (SimileAjax.WindowManager._ghostCoords.left - 16) + "px";
       
  3417             img.style.top = (SimileAjax.WindowManager._ghostCoords.top) + "px";
       
  3418             document.body.appendChild(img);
       
  3419 
       
  3420             SimileAjax.WindowManager._draggingModeIndicatorElmt = img;
       
  3421         }
       
  3422     }
       
  3423 };
       
  3424 
       
  3425 SimileAjax.WindowManager._onBodyKeyUp = function(elmt, evt, target) {
       
  3426     if (SimileAjax.WindowManager._dragging) {
       
  3427         if (evt.keyCode == 17 || evt.keyCode == 16) {
       
  3428             SimileAjax.WindowManager._draggingMode = "";
       
  3429             if (SimileAjax.WindowManager._draggingModeIndicatorElmt != null) {
       
  3430                 document.body.removeChild(SimileAjax.WindowManager._draggingModeIndicatorElmt);
       
  3431                 SimileAjax.WindowManager._draggingModeIndicatorElmt = null;
       
  3432             }
       
  3433         }
       
  3434     }
       
  3435 };
       
  3436 
       
  3437 SimileAjax.WindowManager._onBodyMouseMove = function(elmt, evt, target) {
       
  3438     if (SimileAjax.WindowManager._draggedElement != null) {
       
  3439         var callback = SimileAjax.WindowManager._draggedElementCallback;
       
  3440 
       
  3441         var lastCoords = SimileAjax.WindowManager._lastCoords;
       
  3442         var diffX = evt.clientX - lastCoords.x;
       
  3443         var diffY = evt.clientY - lastCoords.y;
       
  3444 
       
  3445         if (!SimileAjax.WindowManager._dragging) {
       
  3446             if (Math.abs(diffX) > 5 || Math.abs(diffY) > 5) {
       
  3447                 try {
       
  3448                     if ("onDragStart" in callback) {
       
  3449                         callback.onDragStart();
       
  3450                     }
       
  3451 
       
  3452                     if ("ghost" in callback && callback.ghost) {
       
  3453                         var draggedElmt = SimileAjax.WindowManager._draggedElement;
       
  3454 
       
  3455                         SimileAjax.WindowManager._ghostCoords = SimileAjax.DOM.getPageCoordinates(draggedElmt);
       
  3456                         SimileAjax.WindowManager._ghostCoords.left += diffX;
       
  3457                         SimileAjax.WindowManager._ghostCoords.top += diffY;
       
  3458 
       
  3459                         var ghostElmt = draggedElmt.cloneNode(true);
       
  3460                         ghostElmt.style.position = "absolute";
       
  3461                         ghostElmt.style.left = SimileAjax.WindowManager._ghostCoords.left + "px";
       
  3462                         ghostElmt.style.top = SimileAjax.WindowManager._ghostCoords.top + "px";
       
  3463                         ghostElmt.style.zIndex = 1000;
       
  3464                         SimileAjax.Graphics.setOpacity(ghostElmt, 50);
       
  3465 
       
  3466                         document.body.appendChild(ghostElmt);
       
  3467                         callback._ghostElmt = ghostElmt;
       
  3468                     }
       
  3469 
       
  3470                     SimileAjax.WindowManager._dragging = true;
       
  3471                     SimileAjax.WindowManager._lastCoords = { x: evt.clientX, y: evt.clientY };
       
  3472 
       
  3473                     document.body.focus();
       
  3474                 } catch (e) {
       
  3475                     SimileAjax.Debug.exception("WindowManager: Error handling mouse down", e);
       
  3476                     SimileAjax.WindowManager._cancelDragging();
       
  3477                 }
       
  3478             }
       
  3479         } else {
       
  3480             try {
       
  3481                 SimileAjax.WindowManager._lastCoords = { x: evt.clientX, y: evt.clientY };
       
  3482 
       
  3483                 if ("onDragBy" in callback) {
       
  3484                     callback.onDragBy(diffX, diffY);
       
  3485                 }
       
  3486 
       
  3487                 if ("_ghostElmt" in callback) {
       
  3488                     var ghostElmt = callback._ghostElmt;
       
  3489 
       
  3490                     SimileAjax.WindowManager._ghostCoords.left += diffX;
       
  3491                     SimileAjax.WindowManager._ghostCoords.top += diffY;
       
  3492 
       
  3493                     ghostElmt.style.left = SimileAjax.WindowManager._ghostCoords.left + "px";
       
  3494                     ghostElmt.style.top = SimileAjax.WindowManager._ghostCoords.top + "px";
       
  3495                     if (SimileAjax.WindowManager._draggingModeIndicatorElmt != null) {
       
  3496                         var indicatorElmt = SimileAjax.WindowManager._draggingModeIndicatorElmt;
       
  3497 
       
  3498                         indicatorElmt.style.left = (SimileAjax.WindowManager._ghostCoords.left - 16) + "px";
       
  3499                         indicatorElmt.style.top = SimileAjax.WindowManager._ghostCoords.top + "px";
       
  3500                     }
       
  3501 
       
  3502                     if ("droppable" in callback && callback.droppable) {
       
  3503                         var coords = SimileAjax.DOM.getEventPageCoordinates(evt);
       
  3504                         var target = SimileAjax.DOM.hittest(
       
  3505                             coords.x, coords.y,
       
  3506                             [   SimileAjax.WindowManager._ghostElmt,
       
  3507                                 SimileAjax.WindowManager._dropTargetHighlightElement
       
  3508                             ]
       
  3509                         );
       
  3510                         target = SimileAjax.WindowManager._findDropTarget(target);
       
  3511 
       
  3512                         if (target != SimileAjax.WindowManager._potentialDropTarget) {
       
  3513                             if (SimileAjax.WindowManager._dropTargetHighlightElement != null) {
       
  3514                                 document.body.removeChild(SimileAjax.WindowManager._dropTargetHighlightElement);
       
  3515 
       
  3516                                 SimileAjax.WindowManager._dropTargetHighlightElement = null;
       
  3517                                 SimileAjax.WindowManager._potentialDropTarget = null;
       
  3518                             }
       
  3519 
       
  3520                             var droppable = false;
       
  3521                             if (target != null) {
       
  3522                                 if ((!("canDropOn" in callback) || callback.canDropOn(target)) &&
       
  3523                                     (!("canDrop" in target) || target.canDrop(SimileAjax.WindowManager._draggedElement))) {
       
  3524 
       
  3525                                     droppable = true;
       
  3526                                 }
       
  3527                             }
       
  3528 
       
  3529                             if (droppable) {
       
  3530                                 var border = 4;
       
  3531                                 var targetCoords = SimileAjax.DOM.getPageCoordinates(target);
       
  3532                                 var highlight = document.createElement("div");
       
  3533                                 highlight.style.border = border + "px solid yellow";
       
  3534                                 highlight.style.backgroundColor = "yellow";
       
  3535                                 highlight.style.position = "absolute";
       
  3536                                 highlight.style.left = targetCoords.left + "px";
       
  3537                                 highlight.style.top = targetCoords.top + "px";
       
  3538                                 highlight.style.width = (target.offsetWidth - border * 2) + "px";
       
  3539                                 highlight.style.height = (target.offsetHeight - border * 2) + "px";
       
  3540                                 SimileAjax.Graphics.setOpacity(highlight, 30);
       
  3541                                 document.body.appendChild(highlight);
       
  3542 
       
  3543                                 SimileAjax.WindowManager._potentialDropTarget = target;
       
  3544                                 SimileAjax.WindowManager._dropTargetHighlightElement = highlight;
       
  3545                             }
       
  3546                         }
       
  3547                     }
       
  3548                 }
       
  3549             } catch (e) {
       
  3550                 SimileAjax.Debug.exception("WindowManager: Error handling mouse move", e);
       
  3551                 SimileAjax.WindowManager._cancelDragging();
       
  3552             }
       
  3553         }
       
  3554 
       
  3555         SimileAjax.DOM.cancelEvent(evt);
       
  3556         return false;
       
  3557     }
       
  3558 };
       
  3559 
       
  3560 SimileAjax.WindowManager._onBodyMouseUp = function(elmt, evt, target) {
       
  3561     if (SimileAjax.WindowManager._draggedElement != null) {
       
  3562         try {
       
  3563             if (SimileAjax.WindowManager._dragging) {
       
  3564                 var callback = SimileAjax.WindowManager._draggedElementCallback;
       
  3565                 if ("onDragEnd" in callback) {
       
  3566                     callback.onDragEnd();
       
  3567                 }
       
  3568                 if ("droppable" in callback && callback.droppable) {
       
  3569                     var dropped = false;
       
  3570 
       
  3571                     var target = SimileAjax.WindowManager._potentialDropTarget;
       
  3572                     if (target != null) {
       
  3573                         if ((!("canDropOn" in callback) || callback.canDropOn(target)) &&
       
  3574                             (!("canDrop" in target) || target.canDrop(SimileAjax.WindowManager._draggedElement))) {
       
  3575 
       
  3576                             if ("onDropOn" in callback) {
       
  3577                                 callback.onDropOn(target);
       
  3578                             }
       
  3579                             target.ondrop(SimileAjax.WindowManager._draggedElement, SimileAjax.WindowManager._draggingMode);
       
  3580 
       
  3581                             dropped = true;
       
  3582                         }
       
  3583                     }
       
  3584 
       
  3585                     if (!dropped) {
       
  3586                         // TODO: do holywood explosion here
       
  3587                     }
       
  3588                 }
       
  3589             }
       
  3590         } finally {
       
  3591             SimileAjax.WindowManager._cancelDragging();
       
  3592         }
       
  3593 
       
  3594         SimileAjax.DOM.cancelEvent(evt);
       
  3595         return false;
       
  3596     }
       
  3597 };
       
  3598 
       
  3599 SimileAjax.WindowManager._cancelDragging = function() {
       
  3600     var callback = SimileAjax.WindowManager._draggedElementCallback;
       
  3601     if ("_ghostElmt" in callback) {
       
  3602         var ghostElmt = callback._ghostElmt;
       
  3603         document.body.removeChild(ghostElmt);
       
  3604 
       
  3605         delete callback._ghostElmt;
       
  3606     }
       
  3607     if (SimileAjax.WindowManager._dropTargetHighlightElement != null) {
       
  3608         document.body.removeChild(SimileAjax.WindowManager._dropTargetHighlightElement);
       
  3609         SimileAjax.WindowManager._dropTargetHighlightElement = null;
       
  3610     }
       
  3611     if (SimileAjax.WindowManager._draggingModeIndicatorElmt != null) {
       
  3612         document.body.removeChild(SimileAjax.WindowManager._draggingModeIndicatorElmt);
       
  3613         SimileAjax.WindowManager._draggingModeIndicatorElmt = null;
       
  3614     }
       
  3615 
       
  3616     SimileAjax.WindowManager._draggedElement = null;
       
  3617     SimileAjax.WindowManager._draggedElementCallback = null;
       
  3618     SimileAjax.WindowManager._potentialDropTarget = null;
       
  3619     SimileAjax.WindowManager._dropTargetHighlightElement = null;
       
  3620     SimileAjax.WindowManager._lastCoords = null;
       
  3621     SimileAjax.WindowManager._ghostCoords = null;
       
  3622     SimileAjax.WindowManager._draggingMode = "";
       
  3623     SimileAjax.WindowManager._dragging = false;
       
  3624 };
       
  3625 
       
  3626 SimileAjax.WindowManager._findDropTarget = function(elmt) {
       
  3627     while (elmt != null) {
       
  3628         if ("ondrop" in elmt && (typeof elmt.ondrop) == "function") {
       
  3629             break;
       
  3630         }
       
  3631         elmt = elmt.parentNode;
       
  3632     }
       
  3633     return elmt;
       
  3634 };
       
  3635 /*==================================================
       
  3636  *  Timeline API
       
  3637  *
       
  3638  *  This file will load all the Javascript files
       
  3639  *  necessary to make the standard timeline work.
       
  3640  *  It also detects the default locale.
       
  3641  *
       
  3642  *  To run from the MIT copy of Timeline:
       
  3643  *  Include this file in your HTML file as follows:
       
  3644  *
       
  3645  *    <script src="http://api.simile-widgets.org/timeline/2.3.1/timeline-api.js"
       
  3646  *     type="text/javascript"></script>
       
  3647  *
       
  3648  *
       
  3649  * To host the Timeline files on your own server:
       
  3650  *   1) Install the Timeline and Simile-Ajax files onto your webserver using
       
  3651  *      timeline_libraries.zip or timeline_source.zip
       
  3652  *
       
  3653  *   2) Set global js variables used to send parameters to this script:
       
  3654  *        var Timeline_ajax_url -- url for simile-ajax-api.js
       
  3655  *        var Timeline_urlPrefix -- url for the *directory* that contains timeline-api.js
       
  3656  *            Include trailing slash
       
  3657  *        var Timeline_parameters='bundle=true'; // you must set bundle to true if you are using
       
  3658  *                                               // timeline_libraries.zip since only the
       
  3659  *                                               // bundled libraries are included
       
  3660  *
       
  3661  * eg your html page would include
       
  3662  *
       
  3663  *   <script>
       
  3664  *     var Timeline_ajax_url="http://YOUR_SERVER/javascripts/timeline/timeline_ajax/simile-ajax-api.js";
       
  3665  *     var Timeline_urlPrefix='http://YOUR_SERVER/javascripts/timeline/timeline_js/';
       
  3666  *     var Timeline_parameters='bundle=true';
       
  3667  *   </script>
       
  3668  *   <script src="http://YOUR_SERVER/javascripts/timeline/timeline_js/timeline-api.js"
       
  3669  *     type="text/javascript">
       
  3670  *   </script>
       
  3671  *
       
  3672  * SCRIPT PARAMETERS
       
  3673  * This script auto-magically figures out locale and has defaults for other parameters
       
  3674  * To set parameters explicity, set js global variable Timeline_parameters or include as
       
  3675  * parameters on the url using GET style. Eg the two next lines pass the same parameters:
       
  3676  *     Timeline_parameters='bundle=true';                    // pass parameter via js variable
       
  3677  *     <script src="http://....timeline-api.js?bundle=true"  // pass parameter via url
       
  3678  *
       
  3679  * Parameters
       
  3680  *   timeline-use-local-resources --
       
  3681  *   bundle -- true: use the single js bundle file; false: load individual files (for debugging)
       
  3682  *   locales --
       
  3683  *   defaultLocale --
       
  3684  *   forceLocale -- force locale to be a particular value--used for debugging. Normally locale is determined
       
  3685  *                  by browser's and server's locale settings.
       
  3686  *
       
  3687  * DEBUGGING
       
  3688  * If you have a problem with Timeline, the first step is to use the unbundled Javascript files. To do so:
       
  3689  * To use the unbundled Timeline and Ajax libraries
       
  3690  * Change
       
  3691  *   <script src="http://api.simile-widgets.org/timeline/2.3.1/api/timeline-api.js?bundle=true" type="text/javascript"></script>
       
  3692  * To
       
  3693  *   <script>var Timeline_ajax_url = "http://api.simile-widgets.org/ajax/2.2.1/simile-ajax-api.js?bundle=false"</script>
       
  3694  *   <script src="http://api.simile-widgets.org/timeline/2.3.1/api/timeline-api.js?bundle=false" type="text/javascript"></script>
       
  3695  *
       
  3696  * Note that the Ajax version is usually NOT the same as the Timeline version.
       
  3697  * See variable simile_ajax_ver below for the current version
       
  3698  *
       
  3699  *==================================================
       
  3700  */
       
  3701 
       
  3702 (function() {
       
  3703 
       
  3704     var simile_ajax_ver = "2.2.1"; // ===========>>>  current Simile-Ajax version
       
  3705 
       
  3706     var useLocalResources = false;
       
  3707     if (document.location.search.length > 0) {
       
  3708         var params = document.location.search.substr(1).split("&");
       
  3709         for (var i = 0; i < params.length; i++) {
       
  3710             if (params[i] == "timeline-use-local-resources") {
       
  3711                 useLocalResources = true;
       
  3712             }
       
  3713         }
       
  3714     };
       
  3715 
       
  3716     var loadMe = function() {
       
  3717         if ("Timeline" in window) {
       
  3718             return;
       
  3719         }
       
  3720 
       
  3721         window.Timeline = new Object();
       
  3722         window.Timeline.DateTime = window.SimileAjax.DateTime; // for backward compatibility
       
  3723 
       
  3724         var bundle = false;
       
  3725         var javascriptFiles = [
       
  3726             "timeline.js",
       
  3727             "band.js",
       
  3728             "themes.js",
       
  3729             "ethers.js",
       
  3730             "ether-painters.js",
       
  3731             "event-utils.js",
       
  3732             "labellers.js",
       
  3733             "sources.js",
       
  3734             "original-painter.js",
       
  3735             "detailed-painter.js",
       
  3736             "overview-painter.js",
       
  3737             "compact-painter.js",
       
  3738             "decorators.js",
       
  3739             "units.js"
       
  3740         ];
       
  3741         var cssFiles = [
       
  3742             "timeline.css",
       
  3743             "ethers.css",
       
  3744             "events.css"
       
  3745         ];
       
  3746 
       
  3747         var localizedJavascriptFiles = [
       
  3748             "timeline.js",
       
  3749             "labellers.js"
       
  3750         ];
       
  3751         var localizedCssFiles = [
       
  3752         ];
       
  3753 
       
  3754         // ISO-639 language codes, ISO-3166 country codes (2 characters)
       
  3755         var supportedLocales = [
       
  3756             "cs",       // Czech
       
  3757             "de",       // German
       
  3758             "en",       // English
       
  3759             "es",       // Spanish
       
  3760             "fr",       // French
       
  3761             "it",       // Italian
       
  3762             "nl",       // Dutch (The Netherlands)
       
  3763             "ru",       // Russian
       
  3764             "se",       // Swedish
       
  3765             "tr",       // Turkish
       
  3766             "vi",       // Vietnamese
       
  3767             "zh"        // Chinese
       
  3768         ];
       
  3769 
       
  3770         try {
       
  3771             var desiredLocales = [ "en" ],
       
  3772                 defaultServerLocale = "en",
       
  3773                 forceLocale = null;
       
  3774 
       
  3775             var parseURLParameters = function(parameters) {
       
  3776                 var params = parameters.split("&");
       
  3777                 for (var p = 0; p < params.length; p++) {
       
  3778                     var pair = params[p].split("=");
       
  3779                     if (pair[0] == "locales") {
       
  3780                         desiredLocales = desiredLocales.concat(pair[1].split(","));
       
  3781                     } else if (pair[0] == "defaultLocale") {
       
  3782                         defaultServerLocale = pair[1];
       
  3783                     } else if (pair[0] == "forceLocale") {
       
  3784                         forceLocale = pair[1];
       
  3785                         desiredLocales = desiredLocales.concat(pair[1].split(","));
       
  3786                     } else if (pair[0] == "bundle") {
       
  3787                         bundle = pair[1] != "false";
       
  3788                     }
       
  3789                 }
       
  3790             };
       
  3791 
       
  3792             (function() {
       
  3793                 if (typeof Timeline_urlPrefix == "string") {
       
  3794                     Timeline.urlPrefix = Timeline_urlPrefix;
       
  3795                     if (typeof Timeline_parameters == "string") {
       
  3796                         parseURLParameters(Timeline_parameters);
       
  3797                     }
       
  3798                 } else {
       
  3799                     var heads = document.documentElement.getElementsByTagName("head");
       
  3800                     for (var h = 0; h < heads.length; h++) {
       
  3801                         var scripts = heads[h].getElementsByTagName("script");
       
  3802                         for (var s = 0; s < scripts.length; s++) {
       
  3803                             var url = scripts[s].src;
       
  3804                             var i = url.indexOf("timeline-api.js");
       
  3805                             if (i >= 0) {
       
  3806                                 Timeline.urlPrefix = url.substr(0, i);
       
  3807                                 var q = url.indexOf("?");
       
  3808                                 if (q > 0) {
       
  3809                                     parseURLParameters(url.substr(q + 1));
       
  3810                                 }
       
  3811                                 return;
       
  3812                             }
       
  3813                         }
       
  3814                     }
       
  3815                     throw new Error("Failed to derive URL prefix for Timeline API code files");
       
  3816                 }
       
  3817             })();
       
  3818 
       
  3819             var includeJavascriptFiles = function(urlPrefix, filenames) {
       
  3820                 SimileAjax.includeJavascriptFiles(document, urlPrefix, filenames);
       
  3821             }
       
  3822             var includeCssFiles = function(urlPrefix, filenames) {
       
  3823                 SimileAjax.includeCssFiles(document, urlPrefix, filenames);
       
  3824             }
       
  3825 
       
  3826             /*
       
  3827              *  Include non-localized files
       
  3828              */
       
  3829             if (bundle) {
       
  3830                 includeJavascriptFiles(Timeline.urlPrefix, [ "timeline-bundle.js" ]);
       
  3831                 includeCssFiles(Timeline.urlPrefix, [ "timeline-bundle.css" ]);
       
  3832             } else {
       
  3833                 includeJavascriptFiles(Timeline.urlPrefix + "scripts/", javascriptFiles);
       
  3834                 includeCssFiles(Timeline.urlPrefix + "styles/", cssFiles);
       
  3835             }
       
  3836 
       
  3837             /*
       
  3838              *  Include localized files
       
  3839              */
       
  3840             var loadLocale = [];
       
  3841             loadLocale[defaultServerLocale] = true;
       
  3842 
       
  3843             var tryExactLocale = function(locale) {
       
  3844                 for (var l = 0; l < supportedLocales.length; l++) {
       
  3845                     if (locale == supportedLocales[l]) {
       
  3846                         loadLocale[locale] = true;
       
  3847                         return true;
       
  3848                     }
       
  3849                 }
       
  3850                 return false;
       
  3851             }
       
  3852             var tryLocale = function(locale) {
       
  3853                 if (tryExactLocale(locale)) {
       
  3854                     return locale;
       
  3855                 }
       
  3856 
       
  3857                 var dash = locale.indexOf("-");
       
  3858                 if (dash > 0 && tryExactLocale(locale.substr(0, dash))) {
       
  3859                     return locale.substr(0, dash);
       
  3860                 }
       
  3861 
       
  3862                 return null;
       
  3863             }
       
  3864 
       
  3865             for (var l = 0; l < desiredLocales.length; l++) {
       
  3866                 tryLocale(desiredLocales[l]);
       
  3867             }
       
  3868 
       
  3869             var defaultClientLocale = defaultServerLocale;
       
  3870             var defaultClientLocales = ("language" in navigator ? navigator.language : navigator.browserLanguage).split(";");
       
  3871             for (var l = 0; l < defaultClientLocales.length; l++) {
       
  3872                 var locale = tryLocale(defaultClientLocales[l]);
       
  3873                 if (locale != null) {
       
  3874                     defaultClientLocale = locale;
       
  3875                     break;
       
  3876                 }
       
  3877             }
       
  3878 
       
  3879             for (var l = 0; l < supportedLocales.length; l++) {
       
  3880                 var locale = supportedLocales[l];
       
  3881                 if (loadLocale[locale]) {
       
  3882                     includeJavascriptFiles(Timeline.urlPrefix + "scripts/l10n/" + locale + "/", localizedJavascriptFiles);
       
  3883                     includeCssFiles(Timeline.urlPrefix + "styles/l10n/" + locale + "/", localizedCssFiles);
       
  3884                 }
       
  3885             }
       
  3886 
       
  3887             if (forceLocale == null) {
       
  3888               Timeline.serverLocale = defaultServerLocale;
       
  3889               Timeline.clientLocale = defaultClientLocale;
       
  3890             } else {
       
  3891               Timeline.serverLocale = forceLocale;
       
  3892               Timeline.clientLocale = forceLocale;
       
  3893             }
       
  3894         } catch (e) {
       
  3895             alert(e);
       
  3896         }
       
  3897     };
       
  3898 
       
  3899     /*
       
  3900      *  Load SimileAjax if it's not already loaded
       
  3901      */
       
  3902     if (typeof SimileAjax == "undefined") {
       
  3903         window.SimileAjax_onLoad = loadMe;
       
  3904 
       
  3905         var url = useLocalResources ?
       
  3906             "http://127.0.0.1:9999/ajax/api/simile-ajax-api.js?bundle=false" :
       
  3907             "http://api.simile-widgets.org/ajax/" + simile_ajax_ver + "/simile-ajax-api.js";
       
  3908         if (typeof Timeline_ajax_url == "string") {
       
  3909            url = Timeline_ajax_url;
       
  3910         }
       
  3911         var createScriptElement = function() {
       
  3912             var script = document.createElement("script");
       
  3913             script.type = "text/javascript";
       
  3914             script.language = "JavaScript";
       
  3915             script.src = url;
       
  3916             document.getElementsByTagName("head")[0].appendChild(script);
       
  3917         }
       
  3918         if (document.body == null) {
       
  3919             try {
       
  3920                 document.write("<script src='" + url + "' type='text/javascript'></script>");
       
  3921             } catch (e) {
       
  3922                 createScriptElement();
       
  3923             }
       
  3924         } else {
       
  3925             createScriptElement();
       
  3926         }
       
  3927     } else {
       
  3928         loadMe();
       
  3929     }
  1382 })();
  3930 })();
  1383 
  3931 /*=================================================
  1384 
  3932  *
  1385 /* string.js */
  3933  * Coding standards:
  1386 String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"");
  3934  *
  1387 };
  3935  * We aim towards Douglas Crockford's Javascript conventions.
  1388 String.prototype.startsWith=function(A){return this.length>=A.length&&this.substr(0,A.length)==A;
  3936  * See:  http://javascript.crockford.com/code.html
  1389 };
  3937  * See also: http://www.crockford.com/javascript/javascript.html
  1390 String.prototype.endsWith=function(A){return this.length>=A.length&&this.substr(this.length-A.length)==A;
  3938  *
  1391 };
  3939  * That said, this JS code was written before some recent JS
  1392 String.substitute=function(B,D){var A="";
  3940  * support libraries became widely used or available.
  1393 var F=0;
  3941  * In particular, the _ character is used to indicate a class function or
  1394 while(F<B.length-1){var C=B.indexOf("%",F);
  3942  * variable that should be considered private to the class.
  1395 if(C<0||C==B.length-1){break;
  3943  *
  1396 }else{if(C>F&&B.charAt(C-1)=="\\"){A+=B.substring(F,C-1)+"%";
  3944  * The code mostly uses accessor methods for getting/setting the private
  1397 F=C+1;
  3945  * class variables.
  1398 }else{var E=parseInt(B.charAt(C+1));
  3946  *
  1399 if(isNaN(E)||E>=D.length){A+=B.substring(F,C+2);
  3947  * Over time, we'd like to formalize the convention by using support libraries
  1400 }else{A+=B.substring(F,C)+D[E].toString();
  3948  * which enforce privacy in objects.
  1401 }F=C+2;
  3949  *
  1402 }}}if(F<B.length){A+=B.substring(F);
  3950  * We also want to use jslint:  http://www.jslint.com/
  1403 }return A;
  3951  *
  1404 };
  3952  *
  1405 
  3953  *==================================================
  1406 
  3954  */
  1407 /* units.js */
  3955 
  1408 SimileAjax.NativeDateUnit=new Object();
  3956 
  1409 SimileAjax.NativeDateUnit.makeDefaultValue=function(){return new Date();
  3957 
  1410 };
  3958 /*==================================================
  1411 SimileAjax.NativeDateUnit.cloneValue=function(A){return new Date(A.getTime());
  3959  *  Timeline VERSION
  1412 };
  3960  *==================================================
  1413 SimileAjax.NativeDateUnit.getParser=function(A){if(typeof A=="string"){A=A.toLowerCase();
  3961  */
  1414 }return(A=="iso8601"||A=="iso 8601")?SimileAjax.DateTime.parseIso8601DateTime:SimileAjax.DateTime.parseGregorianDateTime;
  3962 // Note: version is also stored in the build.xml file
  1415 };
  3963 Timeline.version = 'pre 2.4.0';  // use format 'pre 1.2.3' for trunk versions
  1416 SimileAjax.NativeDateUnit.parseFromObject=function(A){return SimileAjax.DateTime.parseGregorianDateTime(A);
  3964 Timeline.ajax_lib_version = SimileAjax.version;
  1417 };
  3965 Timeline.display_version = Timeline.version + ' (with Ajax lib ' + Timeline.ajax_lib_version + ')';
  1418 SimileAjax.NativeDateUnit.toNumber=function(A){return A.getTime();
  3966  // cf method Timeline.writeVersion
  1419 };
  3967 
  1420 SimileAjax.NativeDateUnit.fromNumber=function(A){return new Date(A);
  3968 /*==================================================
  1421 };
  3969  *  Timeline
  1422 SimileAjax.NativeDateUnit.compare=function(D,C){var B,A;
  3970  *==================================================
  1423 if(typeof D=="object"){B=D.getTime();
  3971  */
  1424 }else{B=Number(D);
  3972 Timeline.strings = {}; // localization string tables
  1425 }if(typeof C=="object"){A=C.getTime();
  3973 Timeline.HORIZONTAL = 0;
  1426 }else{A=Number(C);
  3974 Timeline.VERTICAL = 1;
  1427 }return B-A;
  3975 Timeline._defaultTheme = null;
  1428 };
  3976 
  1429 SimileAjax.NativeDateUnit.earlier=function(B,A){return SimileAjax.NativeDateUnit.compare(B,A)<0?B:A;
  3977 Timeline.getDefaultLocale = function() {
  1430 };
  3978     return Timeline.clientLocale;
  1431 SimileAjax.NativeDateUnit.later=function(B,A){return SimileAjax.NativeDateUnit.compare(B,A)>0?B:A;
  3979 };
  1432 };
  3980 
  1433 SimileAjax.NativeDateUnit.change=function(A,B){return new Date(A.getTime()+B);
  3981 Timeline.create = function(elmt, bandInfos, orientation, unit) {
  1434 };
  3982     if (Timeline.timelines == null) {
  1435 
  3983         Timeline.timelines = [];
  1436 
  3984         // Timeline.timelines array can have null members--Timelines that
  1437 /* window-manager.js */
  3985         // once existed on the page, but were later disposed of.
  1438 SimileAjax.WindowManager={_initialized:false,_listeners:[],_draggedElement:null,_draggedElementCallback:null,_dropTargetHighlightElement:null,_lastCoords:null,_ghostCoords:null,_draggingMode:"",_dragging:false,_layers:[]};
  3986     }
  1439 SimileAjax.WindowManager.initialize=function(){if(SimileAjax.WindowManager._initialized){return ;
  3987 
  1440 }SimileAjax.DOM.registerEvent(document.body,"mousedown",SimileAjax.WindowManager._onBodyMouseDown);
  3988     var timelineID = Timeline.timelines.length;
  1441 SimileAjax.DOM.registerEvent(document.body,"mousemove",SimileAjax.WindowManager._onBodyMouseMove);
  3989     Timeline.timelines[timelineID] = null; // placeholder until we have the object
  1442 SimileAjax.DOM.registerEvent(document.body,"mouseup",SimileAjax.WindowManager._onBodyMouseUp);
  3990     var new_tl = new Timeline._Impl(elmt, bandInfos, orientation, unit,
  1443 SimileAjax.DOM.registerEvent(document,"keydown",SimileAjax.WindowManager._onBodyKeyDown);
  3991       timelineID);
  1444 SimileAjax.DOM.registerEvent(document,"keyup",SimileAjax.WindowManager._onBodyKeyUp);
  3992     Timeline.timelines[timelineID] = new_tl;
  1445 SimileAjax.WindowManager._layers.push({index:0});
  3993     return new_tl;
  1446 SimileAjax.WindowManager._historyListener={onBeforeUndoSeveral:function(){},onAfterUndoSeveral:function(){},onBeforeUndo:function(){},onAfterUndo:function(){},onBeforeRedoSeveral:function(){},onAfterRedoSeveral:function(){},onBeforeRedo:function(){},onAfterRedo:function(){}};
  3994 };
  1447 SimileAjax.History.addListener(SimileAjax.WindowManager._historyListener);
  3995 
  1448 SimileAjax.WindowManager._initialized=true;
  3996 Timeline.createBandInfo = function(params) {
  1449 };
  3997     var theme = ("theme" in params) ? params.theme : Timeline.getDefaultTheme();
  1450 SimileAjax.WindowManager.getBaseLayer=function(){SimileAjax.WindowManager.initialize();
  3998 
  1451 return SimileAjax.WindowManager._layers[0];
  3999     var eventSource = ("eventSource" in params) ? params.eventSource : null;
  1452 };
  4000 
  1453 SimileAjax.WindowManager.getHighestLayer=function(){SimileAjax.WindowManager.initialize();
  4001     var etherParams = {
  1454 return SimileAjax.WindowManager._layers[SimileAjax.WindowManager._layers.length-1];
  4002         interval:           SimileAjax.DateTime.gregorianUnitLengths[params.intervalUnit],
  1455 };
  4003         pixelsPerInterval: params.intervalPixels,
  1456 SimileAjax.WindowManager.registerEventWithObject=function(D,A,E,B,C){SimileAjax.WindowManager.registerEvent(D,A,function(G,F,H){return E[B].call(E,G,F,H);
  4004 	theme: theme
  1457 },C);
  4005     };
  1458 };
  4006     if ('startsOn' in params || 'endsOn' in params) {
  1459 SimileAjax.WindowManager.registerEvent=function(D,B,E,C){if(C==null){C=SimileAjax.WindowManager.getHighestLayer();
  4007 	if ('startsOn' in params) {
  1460 }var A=function(G,F,I){if(SimileAjax.WindowManager._canProcessEventAtLayer(C)){SimileAjax.WindowManager._popToLayer(C.index);
  4008 	    etherParams.startsOn = params.startsOn;
  1461 try{E(G,F,I);
  4009 	}
  1462 }catch(H){SimileAjax.Debug.exception(H);
  4010 	if ('endsOn' in params) {
  1463 }}SimileAjax.DOM.cancelEvent(F);
  4011 	    etherParams.endsOn = params.endsOn;
  1464 return false;
  4012 	}
  1465 };
  4013     } else {
  1466 SimileAjax.DOM.registerEvent(D,B,A);
  4014 	etherParams.centersOn = ("date" in params) ? params.date : new Date();
  1467 };
  4015     }
  1468 SimileAjax.WindowManager.pushLayer=function(C,D,B){var A={onPop:C,index:SimileAjax.WindowManager._layers.length,ephemeral:(D),elmt:B};
  4016     var ether = new Timeline.LinearEther(etherParams);
  1469 SimileAjax.WindowManager._layers.push(A);
  4017 
  1470 return A;
  4018     var etherPainter = new Timeline.GregorianEtherPainter({
  1471 };
  4019         unit:       params.intervalUnit,
  1472 SimileAjax.WindowManager.popLayer=function(B){for(var A=1;
  4020         multiple:   ("multiple" in params) ? params.multiple : 1,
  1473 A<SimileAjax.WindowManager._layers.length;
  4021         theme:      theme,
  1474 A++){if(SimileAjax.WindowManager._layers[A]==B){SimileAjax.WindowManager._popToLayer(A-1);
  4022         align:      ("align" in params) ? params.align : undefined
  1475 break;
  4023     });
  1476 }}};
  4024 
  1477 SimileAjax.WindowManager.popAllLayers=function(){SimileAjax.WindowManager._popToLayer(0);
  4025     var eventPainterParams = {
  1478 };
  4026         showText:   ("showEventText" in params) ? params.showEventText : true,
  1479 SimileAjax.WindowManager.registerForDragging=function(B,C,A){SimileAjax.WindowManager.registerEvent(B,"mousedown",function(E,D,F){SimileAjax.WindowManager._handleMouseDown(E,D,C);
  4027         theme:      theme
  1480 },A);
  4028     };
  1481 };
  4029     // pass in custom parameters for the event painter
  1482 SimileAjax.WindowManager._popToLayer=function(C){while(C+1<SimileAjax.WindowManager._layers.length){try{var A=SimileAjax.WindowManager._layers.pop();
  4030     if ("eventPainterParams" in params) {
  1483 if(A.onPop!=null){A.onPop();
  4031         for (var prop in params.eventPainterParams) {
  1484 }}catch(B){}}};
  4032             eventPainterParams[prop] = params.eventPainterParams[prop];
  1485 SimileAjax.WindowManager._canProcessEventAtLayer=function(B){if(B.index==(SimileAjax.WindowManager._layers.length-1)){return true;
  4033         }
  1486 }for(var A=B.index+1;
  4034     }
  1487 A<SimileAjax.WindowManager._layers.length;
  4035 
  1488 A++){if(!SimileAjax.WindowManager._layers[A].ephemeral){return false;
  4036     if ("trackHeight" in params) {
  1489 }}return true;
  4037         eventPainterParams.trackHeight = params.trackHeight;
  1490 };
  4038     }
  1491 SimileAjax.WindowManager.cancelPopups=function(A){var F=(A)?SimileAjax.DOM.getEventPageCoordinates(A):{x:-1,y:-1};
  4039     if ("trackGap" in params) {
  1492 var E=SimileAjax.WindowManager._layers.length-1;
  4040         eventPainterParams.trackGap = params.trackGap;
  1493 while(E>0&&SimileAjax.WindowManager._layers[E].ephemeral){var D=SimileAjax.WindowManager._layers[E];
  4041     }
  1494 if(D.elmt!=null){var C=D.elmt;
  4042 
  1495 var B=SimileAjax.DOM.getPageCoordinates(C);
  4043     var layout = ("overview" in params && params.overview) ? "overview" : ("layout" in params ? params.layout : "original");
  1496 if(F.x>=B.left&&F.x<(B.left+C.offsetWidth)&&F.y>=B.top&&F.y<(B.top+C.offsetHeight)){break;
  4044     var eventPainter;
  1497 }}E--;
  4045     if ("eventPainter" in params) {
  1498 }SimileAjax.WindowManager._popToLayer(E);
  4046         eventPainter = new params.eventPainter(eventPainterParams);
  1499 };
  4047     } else {
  1500 SimileAjax.WindowManager._onBodyMouseDown=function(B,A,C){if(!("eventPhase" in A)||A.eventPhase==A.BUBBLING_PHASE){SimileAjax.WindowManager.cancelPopups(A);
  4048         switch (layout) {
  1501 }};
  4049             case "overview" :
  1502 SimileAjax.WindowManager._handleMouseDown=function(B,A,C){SimileAjax.WindowManager._draggedElement=B;
  4050                 eventPainter = new Timeline.OverviewEventPainter(eventPainterParams);
  1503 SimileAjax.WindowManager._draggedElementCallback=C;
  4051                 break;
  1504 SimileAjax.WindowManager._lastCoords={x:A.clientX,y:A.clientY};
  4052             case "detailed" :
  1505 SimileAjax.DOM.cancelEvent(A);
  4053                 eventPainter = new Timeline.DetailedEventPainter(eventPainterParams);
  1506 return false;
  4054                 break;
  1507 };
  4055             default:
  1508 SimileAjax.WindowManager._onBodyKeyDown=function(C,A,D){if(SimileAjax.WindowManager._dragging){if(A.keyCode==27){SimileAjax.WindowManager._cancelDragging();
  4056                 eventPainter = new Timeline.OriginalEventPainter(eventPainterParams);
  1509 }else{if((A.keyCode==17||A.keyCode==16)&&SimileAjax.WindowManager._draggingMode!="copy"){SimileAjax.WindowManager._draggingMode="copy";
  4057         }
  1510 var B=SimileAjax.Graphics.createTranslucentImage(SimileAjax.urlPrefix+"data/timeline/copy.png");
  4058     }
  1511 B.style.position="absolute";
  4059 
  1512 B.style.left=(SimileAjax.WindowManager._ghostCoords.left-16)+"px";
  4060     return {
  1513 B.style.top=(SimileAjax.WindowManager._ghostCoords.top)+"px";
  4061         width:          params.width,
  1514 document.body.appendChild(B);
  4062         eventSource:    eventSource,
  1515 SimileAjax.WindowManager._draggingModeIndicatorElmt=B;
  4063         timeZone:       ("timeZone" in params) ? params.timeZone : 0,
  1516 }}}};
  4064         ether:          ether,
  1517 SimileAjax.WindowManager._onBodyKeyUp=function(B,A,C){if(SimileAjax.WindowManager._dragging){if(A.keyCode==17||A.keyCode==16){SimileAjax.WindowManager._draggingMode="";
  4065         etherPainter:   etherPainter,
  1518 if(SimileAjax.WindowManager._draggingModeIndicatorElmt!=null){document.body.removeChild(SimileAjax.WindowManager._draggingModeIndicatorElmt);
  4066         eventPainter:   eventPainter,
  1519 SimileAjax.WindowManager._draggingModeIndicatorElmt=null;
  4067         theme:          theme,
  1520 }}}};
  4068         zoomIndex:      ("zoomIndex" in params) ? params.zoomIndex : 0,
  1521 SimileAjax.WindowManager._onBodyMouseMove=function(A,N,H){if(SimileAjax.WindowManager._draggedElement!=null){var P=SimileAjax.WindowManager._draggedElementCallback;
  4069         zoomSteps:      ("zoomSteps" in params) ? params.zoomSteps : null
  1522 var E=SimileAjax.WindowManager._lastCoords;
  4070     };
  1523 var M=N.clientX-E.x;
  4071 };
  1524 var J=N.clientY-E.y;
  4072 
  1525 if(!SimileAjax.WindowManager._dragging){if(Math.abs(M)>5||Math.abs(J)>5){try{if("onDragStart" in P){P.onDragStart();
  4073 Timeline.createHotZoneBandInfo = function(params) {
  1526 }if("ghost" in P&&P.ghost){var K=SimileAjax.WindowManager._draggedElement;
  4074     var theme = ("theme" in params) ? params.theme : Timeline.getDefaultTheme();
  1527 SimileAjax.WindowManager._ghostCoords=SimileAjax.DOM.getPageCoordinates(K);
  4075 
  1528 SimileAjax.WindowManager._ghostCoords.left+=M;
  4076     var eventSource = ("eventSource" in params) ? params.eventSource : null;
  1529 SimileAjax.WindowManager._ghostCoords.top+=J;
  4077 
  1530 var O=K.cloneNode(true);
  4078     var ether = new Timeline.HotZoneEther({
  1531 O.style.position="absolute";
  4079         centersOn:          ("date" in params) ? params.date : new Date(),
  1532 O.style.left=SimileAjax.WindowManager._ghostCoords.left+"px";
  4080         interval:           SimileAjax.DateTime.gregorianUnitLengths[params.intervalUnit],
  1533 O.style.top=SimileAjax.WindowManager._ghostCoords.top+"px";
  4081         pixelsPerInterval:  params.intervalPixels,
  1534 O.style.zIndex=1000;
  4082         zones:              params.zones,
  1535 SimileAjax.Graphics.setOpacity(O,50);
  4083         theme:              theme
  1536 document.body.appendChild(O);
  4084     });
  1537 P._ghostElmt=O;
  4085 
  1538 }SimileAjax.WindowManager._dragging=true;
  4086     var etherPainter = new Timeline.HotZoneGregorianEtherPainter({
  1539 SimileAjax.WindowManager._lastCoords={x:N.clientX,y:N.clientY};
  4087         unit:       params.intervalUnit,
  1540 document.body.focus();
  4088         zones:      params.zones,
  1541 }catch(G){SimileAjax.Debug.exception("WindowManager: Error handling mouse down",G);
  4089         theme:      theme,
  1542 SimileAjax.WindowManager._cancelDragging();
  4090         align:      ("align" in params) ? params.align : undefined
  1543 }}}else{try{SimileAjax.WindowManager._lastCoords={x:N.clientX,y:N.clientY};
  4091     });
  1544 if("onDragBy" in P){P.onDragBy(M,J);
  4092 
  1545 }if("_ghostElmt" in P){var O=P._ghostElmt;
  4093     var eventPainterParams = {
  1546 SimileAjax.WindowManager._ghostCoords.left+=M;
  4094         showText:   ("showEventText" in params) ? params.showEventText : true,
  1547 SimileAjax.WindowManager._ghostCoords.top+=J;
  4095         theme:      theme
  1548 O.style.left=SimileAjax.WindowManager._ghostCoords.left+"px";
  4096     };
  1549 O.style.top=SimileAjax.WindowManager._ghostCoords.top+"px";
  4097     // pass in custom parameters for the event painter
  1550 if(SimileAjax.WindowManager._draggingModeIndicatorElmt!=null){var I=SimileAjax.WindowManager._draggingModeIndicatorElmt;
  4098     if ("eventPainterParams" in params) {
  1551 I.style.left=(SimileAjax.WindowManager._ghostCoords.left-16)+"px";
  4099         for (var prop in params.eventPainterParams) {
  1552 I.style.top=SimileAjax.WindowManager._ghostCoords.top+"px";
  4100             eventPainterParams[prop] = params.eventPainterParams[prop];
  1553 }if("droppable" in P&&P.droppable){var L=SimileAjax.DOM.getEventPageCoordinates(N);
  4101         }
  1554 var H=SimileAjax.DOM.hittest(L.x,L.y,[SimileAjax.WindowManager._ghostElmt,SimileAjax.WindowManager._dropTargetHighlightElement]);
  4102     }
  1555 H=SimileAjax.WindowManager._findDropTarget(H);
  4103     if ("trackHeight" in params) {
  1556 if(H!=SimileAjax.WindowManager._potentialDropTarget){if(SimileAjax.WindowManager._dropTargetHighlightElement!=null){document.body.removeChild(SimileAjax.WindowManager._dropTargetHighlightElement);
  4104         eventPainterParams.trackHeight = params.trackHeight;
  1557 SimileAjax.WindowManager._dropTargetHighlightElement=null;
  4105     }
  1558 SimileAjax.WindowManager._potentialDropTarget=null;
  4106     if ("trackGap" in params) {
  1559 }var F=false;
  4107         eventPainterParams.trackGap = params.trackGap;
  1560 if(H!=null){if((!("canDropOn" in P)||P.canDropOn(H))&&(!("canDrop" in H)||H.canDrop(SimileAjax.WindowManager._draggedElement))){F=true;
  4108     }
  1561 }}if(F){var C=4;
  4109 
  1562 var D=SimileAjax.DOM.getPageCoordinates(H);
  4110     var layout = ("overview" in params && params.overview) ? "overview" : ("layout" in params ? params.layout : "original");
  1563 var B=document.createElement("div");
  4111     var eventPainter;
  1564 B.style.border=C+"px solid yellow";
  4112     if ("eventPainter" in params) {
  1565 B.style.backgroundColor="yellow";
  4113         eventPainter = new params.eventPainter(eventPainterParams);
  1566 B.style.position="absolute";
  4114     } else {
  1567 B.style.left=D.left+"px";
  4115         switch (layout) {
  1568 B.style.top=D.top+"px";
  4116             case "overview" :
  1569 B.style.width=(H.offsetWidth-C*2)+"px";
  4117                 eventPainter = new Timeline.OverviewEventPainter(eventPainterParams);
  1570 B.style.height=(H.offsetHeight-C*2)+"px";
  4118                 break;
  1571 SimileAjax.Graphics.setOpacity(B,30);
  4119             case "detailed" :
  1572 document.body.appendChild(B);
  4120                 eventPainter = new Timeline.DetailedEventPainter(eventPainterParams);
  1573 SimileAjax.WindowManager._potentialDropTarget=H;
  4121                 break;
  1574 SimileAjax.WindowManager._dropTargetHighlightElement=B;
  4122             default:
  1575 }}}}}catch(G){SimileAjax.Debug.exception("WindowManager: Error handling mouse move",G);
  4123                 eventPainter = new Timeline.OriginalEventPainter(eventPainterParams);
  1576 SimileAjax.WindowManager._cancelDragging();
  4124         }
  1577 }}SimileAjax.DOM.cancelEvent(N);
  4125     }
  1578 return false;
  4126     return {
  1579 }};
  4127         width:          params.width,
  1580 SimileAjax.WindowManager._onBodyMouseUp=function(B,A,C){if(SimileAjax.WindowManager._draggedElement!=null){try{if(SimileAjax.WindowManager._dragging){var E=SimileAjax.WindowManager._draggedElementCallback;
  4128         eventSource:    eventSource,
  1581 if("onDragEnd" in E){E.onDragEnd();
  4129         timeZone:       ("timeZone" in params) ? params.timeZone : 0,
  1582 }if("droppable" in E&&E.droppable){var D=false;
  4130         ether:          ether,
  1583 var C=SimileAjax.WindowManager._potentialDropTarget;
  4131         etherPainter:   etherPainter,
  1584 if(C!=null){if((!("canDropOn" in E)||E.canDropOn(C))&&(!("canDrop" in C)||C.canDrop(SimileAjax.WindowManager._draggedElement))){if("onDropOn" in E){E.onDropOn(C);
  4132         eventPainter:   eventPainter,
  1585 }C.ondrop(SimileAjax.WindowManager._draggedElement,SimileAjax.WindowManager._draggingMode);
  4133         theme:          theme,
  1586 D=true;
  4134         zoomIndex:      ("zoomIndex" in params) ? params.zoomIndex : 0,
  1587 }}if(!D){}}}}finally{SimileAjax.WindowManager._cancelDragging();
  4135         zoomSteps:      ("zoomSteps" in params) ? params.zoomSteps : null
  1588 }SimileAjax.DOM.cancelEvent(A);
  4136     };
  1589 return false;
  4137 };
  1590 }};
  4138 
  1591 SimileAjax.WindowManager._cancelDragging=function(){var B=SimileAjax.WindowManager._draggedElementCallback;
  4139 Timeline.getDefaultTheme = function() {
  1592 if("_ghostElmt" in B){var A=B._ghostElmt;
  4140     if (Timeline._defaultTheme == null) {
  1593 document.body.removeChild(A);
  4141         Timeline._defaultTheme = Timeline.ClassicTheme.create(Timeline.getDefaultLocale());
  1594 delete B._ghostElmt;
  4142     }
  1595 }if(SimileAjax.WindowManager._dropTargetHighlightElement!=null){document.body.removeChild(SimileAjax.WindowManager._dropTargetHighlightElement);
  4143     return Timeline._defaultTheme;
  1596 SimileAjax.WindowManager._dropTargetHighlightElement=null;
  4144 };
  1597 }if(SimileAjax.WindowManager._draggingModeIndicatorElmt!=null){document.body.removeChild(SimileAjax.WindowManager._draggingModeIndicatorElmt);
  4145 
  1598 SimileAjax.WindowManager._draggingModeIndicatorElmt=null;
  4146 Timeline.setDefaultTheme = function(theme) {
  1599 }SimileAjax.WindowManager._draggedElement=null;
  4147     Timeline._defaultTheme = theme;
  1600 SimileAjax.WindowManager._draggedElementCallback=null;
  4148 };
  1601 SimileAjax.WindowManager._potentialDropTarget=null;
  4149 
  1602 SimileAjax.WindowManager._dropTargetHighlightElement=null;
  4150 Timeline.loadXML = function(url, f) {
  1603 SimileAjax.WindowManager._lastCoords=null;
  4151     var fError = function(statusText, status, xmlhttp) {
  1604 SimileAjax.WindowManager._ghostCoords=null;
  4152         alert("Failed to load data xml from " + url + "\n" + statusText);
  1605 SimileAjax.WindowManager._draggingMode="";
  4153     };
  1606 SimileAjax.WindowManager._dragging=false;
  4154     var fDone = function(xmlhttp) {
  1607 };
  4155         var xml = xmlhttp.responseXML;
  1608 SimileAjax.WindowManager._findDropTarget=function(A){while(A!=null){if("ondrop" in A&&(typeof A.ondrop)=="function"){break;
  4156         if (!xml.documentElement && xmlhttp.responseStream) {
  1609 }A=A.parentNode;
  4157             xml.load(xmlhttp.responseStream);
  1610 }return A;
  4158         }
  1611 };
  4159         f(xml, url);
  1612 
  4160     };
  1613 
  4161     SimileAjax.XmlHttp.get(url, fError, fDone);
  1614 /* xmlhttp.js */
  4162 };
  1615 SimileAjax.XmlHttp=new Object();
  4163 
  1616 SimileAjax.XmlHttp._onReadyStateChange=function(A,D,B){switch(A.readyState){case 4:try{if(A.status==0||A.status==200){if(B){B(A);
  4164 
  1617 }}else{if(D){D(A.statusText,A.status,A);
  4165 Timeline.loadJSON = function(url, f) {
  1618 }}}catch(C){SimileAjax.Debug.exception("XmlHttp: Error handling onReadyStateChange",C);
  4166     var fError = function(statusText, status, xmlhttp) {
  1619 }break;
  4167         alert("Failed to load json data from " + url + "\n" + statusText);
  1620 }};
  4168     };
  1621 SimileAjax.XmlHttp._createRequest=function(){if(SimileAjax.Platform.browser.isIE){var A=["Msxml2.XMLHTTP","Microsoft.XMLHTTP","Msxml2.XMLHTTP.4.0"];
  4169     var fDone = function(xmlhttp) {
  1622 for(var B=0;
  4170         f(eval('(' + xmlhttp.responseText + ')'), url);
  1623 B<A.length;
  4171     };
  1624 B++){try{var C=A[B];
  4172     SimileAjax.XmlHttp.get(url, fError, fDone);
  1625 var D=function(){return new ActiveXObject(C);
  4173 };
  1626 };
  4174 
  1627 var F=D();
  4175 Timeline.getTimelineFromID = function(timelineID) {
  1628 SimileAjax.XmlHttp._createRequest=D;
  4176     return Timeline.timelines[timelineID];
  1629 return F;
  4177 };
  1630 }catch(E){}}}try{var D=function(){return new XMLHttpRequest();
  4178 
  1631 };
  4179 // Write the current Timeline version as the contents of element with id el_id
  1632 var F=D();
  4180 Timeline.writeVersion = function(el_id) {
  1633 SimileAjax.XmlHttp._createRequest=D;
  4181   document.getElementById(el_id).innerHTML = this.display_version;
  1634 return F;
  4182 };
  1635 }catch(E){throw new Error("Failed to create an XMLHttpRequest object");
  4183 
  1636 }};
  4184 
  1637 SimileAjax.XmlHttp.get=function(A,D,C){var B=SimileAjax.XmlHttp._createRequest();
  4185 
  1638 B.open("GET",A,true);
  4186 /*==================================================
  1639 B.onreadystatechange=function(){SimileAjax.XmlHttp._onReadyStateChange(B,D,C);
  4187  *  Timeline Implementation object
  1640 };
  4188  *==================================================
  1641 B.send(null);
  4189  */
  1642 };
  4190 Timeline._Impl = function(elmt, bandInfos, orientation, unit, timelineID) {
  1643 SimileAjax.XmlHttp.post=function(B,A,E,D){var C=SimileAjax.XmlHttp._createRequest();
  4191     SimileAjax.WindowManager.initialize();
  1644 C.open("POST",B,true);
  4192 
  1645 C.onreadystatechange=function(){SimileAjax.XmlHttp._onReadyStateChange(C,E,D);
  4193     this._containerDiv = elmt;
  1646 };
  4194 
  1647 C.send(A);
  4195     this._bandInfos = bandInfos;
  1648 };
  4196     this._orientation = orientation == null ? Timeline.HORIZONTAL : orientation;
  1649 SimileAjax.XmlHttp._forceXML=function(A){try{A.overrideMimeType("text/xml");
  4197     this._unit = (unit != null) ? unit : SimileAjax.NativeDateUnit;
  1650 }catch(B){A.setrequestheader("Content-Type","text/xml");
  4198     this._starting = true; // is the Timeline being created? Used by autoWidth
  1651 }};
  4199                            // functions
  1652 
  4200     this._autoResizing = false;
  1653 /******** end of simile-ajax-bundle.js ********/
  4201 
  1654 
  4202     // autoWidth is a "public" property of the Timeline object
  1655 /******** start of simile-timeline-bundle.js ********/
  4203     this.autoWidth = bandInfos && bandInfos[0] && bandInfos[0].theme &&
  1656 
  4204                      bandInfos[0].theme.autoWidth;
  1657 /* band.js */
  4205     this.autoWidthAnimationTime = bandInfos && bandInfos[0] && bandInfos[0].theme &&
  1658 Timeline._Band=function(B,C,A){if(B!==undefined){this.initialize(B,C,A);
  4206                      bandInfos[0].theme.autoWidthAnimationTime;
  1659 }};
  4207     this.timelineID = timelineID; // also public attribute
  1660 Timeline._Band.prototype.initialize=function(F,G,B){if(F.autoWidth&&typeof G.width=="string"){G.width=G.width.indexOf("%")>-1?0:parseInt(G.width);
  4208     this.timeline_start = bandInfos && bandInfos[0] && bandInfos[0].theme &&
  1661 }this._timeline=F;
  4209                      bandInfos[0].theme.timeline_start;
  1662 this._bandInfo=G;
  4210     this.timeline_stop  = bandInfos && bandInfos[0] && bandInfos[0].theme &&
  1663 this._index=B;
  4211                      bandInfos[0].theme.timeline_stop;
  1664 this._locale=("locale" in G)?G.locale:Timeline.getDefaultLocale();
  4212     this.timeline_at_start = false; // already at start or stop? Then won't
  1665 this._timeZone=("timeZone" in G)?G.timeZone:0;
  4213     this.timeline_at_stop = false;  // try to move further in the wrong direction
  1666 this._labeller=("labeller" in G)?G.labeller:(("createLabeller" in F.getUnit())?F.getUnit().createLabeller(this._locale,this._timeZone):new Timeline.GregorianDateLabeller(this._locale,this._timeZone));
  4214 
  1667 this._theme=G.theme;
  4215     this._initialize();
  1668 this._zoomIndex=("zoomIndex" in G)?G.zoomIndex:0;
  4216 };
  1669 this._zoomSteps=("zoomSteps" in G)?G.zoomSteps:null;
  4217 
  1670 this._dragging=false;
  4218 //
  1671 this._changing=false;
  4219 // Public functions used by client sw
  1672 this._originalScrollSpeed=5;
  4220 //
  1673 this._scrollSpeed=this._originalScrollSpeed;
  4221 Timeline._Impl.prototype.dispose = function() {
  1674 this._onScrollListeners=[];
  4222     for (var i = 0; i < this._bands.length; i++) {
  1675 var A=this;
  4223         this._bands[i].dispose();
  1676 this._syncWithBand=null;
  4224     }
  1677 this._syncWithBandHandler=function(H){A._onHighlightBandScroll();
  4225     this._bands = null;
  1678 };
  4226     this._bandInfos = null;
  1679 this._selectorListener=function(H){A._onHighlightBandScroll();
  4227     this._containerDiv.innerHTML = "";
  1680 };
  4228     // remove from array of Timelines
  1681 var D=this._timeline.getDocument().createElement("div");
  4229     Timeline.timelines[this.timelineID] = null;
  1682 D.className="timeline-band-input";
  4230 };
  1683 this._timeline.addDiv(D);
  4231 
  1684 this._keyboardInput=document.createElement("input");
  4232 Timeline._Impl.prototype.getBandCount = function() {
  1685 this._keyboardInput.type="text";
  4233     return this._bands.length;
  1686 D.appendChild(this._keyboardInput);
  4234 };
  1687 SimileAjax.DOM.registerEventWithObject(this._keyboardInput,"keydown",this,"_onKeyDown");
  4235 
  1688 SimileAjax.DOM.registerEventWithObject(this._keyboardInput,"keyup",this,"_onKeyUp");
  4236 Timeline._Impl.prototype.getBand = function(index) {
  1689 this._div=this._timeline.getDocument().createElement("div");
  4237     return this._bands[index];
  1690 this._div.id="timeline-band-"+B;
  4238 };
  1691 this._div.className="timeline-band timeline-band-"+B;
  4239 
  1692 this._timeline.addDiv(this._div);
  4240 Timeline._Impl.prototype.finishedEventLoading = function() {
  1693 SimileAjax.DOM.registerEventWithObject(this._div,"mousedown",this,"_onMouseDown");
  4241     // Called by client after events have been loaded into Timeline
  1694 SimileAjax.DOM.registerEventWithObject(this._div,"mousemove",this,"_onMouseMove");
  4242     // Only used if the client has set autoWidth
  1695 SimileAjax.DOM.registerEventWithObject(this._div,"mouseup",this,"_onMouseUp");
  4243     // Sets width to Timeline's requested amount and will shrink down the div if
  1696 SimileAjax.DOM.registerEventWithObject(this._div,"mouseout",this,"_onMouseOut");
  4244     // need be.
  1697 SimileAjax.DOM.registerEventWithObject(this._div,"dblclick",this,"_onDblClick");
  4245     this._autoWidthCheck(true);
  1698 var E=this._theme!=null?this._theme.mouseWheel:"scroll";
  4246     this._starting = false;
  1699 if(E==="zoom"||E==="scroll"||this._zoomSteps){if(SimileAjax.Platform.browser.isFirefox){SimileAjax.DOM.registerEventWithObject(this._div,"DOMMouseScroll",this,"_onMouseScroll");
  4247 };
  1700 }else{SimileAjax.DOM.registerEventWithObject(this._div,"mousewheel",this,"_onMouseScroll");
  4248 
  1701 }}this._innerDiv=this._timeline.getDocument().createElement("div");
  4249 Timeline._Impl.prototype.layout = function() {
  1702 this._innerDiv.className="timeline-band-inner";
  4250     // called by client when browser is resized
  1703 this._div.appendChild(this._innerDiv);
  4251     this._autoWidthCheck(true);
  1704 this._ether=G.ether;
  4252     this._distributeWidths();
  1705 G.ether.initialize(this,F);
  4253 };
  1706 this._etherPainter=G.etherPainter;
  4254 
  1707 G.etherPainter.initialize(this,F);
  4255 Timeline._Impl.prototype.paint = function() {
  1708 this._eventSource=G.eventSource;
  4256     for (var i = 0; i < this._bands.length; i++) {
  1709 if(this._eventSource){this._eventListener={onAddMany:function(){A._onAddMany();
  4257         this._bands[i].paint();
  1710 },onClear:function(){A._onClear();
  4258     }
  1711 }};
  4259 };
  1712 this._eventSource.addListener(this._eventListener);
  4260 
  1713 }this._eventPainter=G.eventPainter;
  4261 Timeline._Impl.prototype.getDocument = function() {
  1714 this._eventTracksNeeded=0;
  4262     return this._containerDiv.ownerDocument;
  1715 this._eventTrackIncrement=0;
  4263 };
  1716 G.eventPainter.initialize(this,F);
  4264 
  1717 this._decorators=("decorators" in G)?G.decorators:[];
  4265 Timeline._Impl.prototype.addDiv = function(div) {
  1718 for(var C=0;
  4266     this._containerDiv.appendChild(div);
  1719 C<this._decorators.length;
  4267 };
  1720 C++){this._decorators[C].initialize(this,F);
  4268 
  1721 }};
  4269 Timeline._Impl.prototype.removeDiv = function(div) {
  1722 Timeline._Band.SCROLL_MULTIPLES=5;
  4270     this._containerDiv.removeChild(div);
  1723 Timeline._Band.prototype.dispose=function(){this.closeBubble();
  4271 };
  1724 if(this._eventSource){this._eventSource.removeListener(this._eventListener);
  4272 
  1725 this._eventListener=null;
  4273 Timeline._Impl.prototype.isHorizontal = function() {
  1726 this._eventSource=null;
  4274     return this._orientation == Timeline.HORIZONTAL;
  1727 }this._timeline=null;
  4275 };
  1728 this._bandInfo=null;
  4276 
  1729 this._labeller=null;
  4277 Timeline._Impl.prototype.isVertical = function() {
  1730 this._ether=null;
  4278     return this._orientation == Timeline.VERTICAL;
  1731 this._etherPainter=null;
  4279 };
  1732 this._eventPainter=null;
  4280 
  1733 this._decorators=null;
  4281 Timeline._Impl.prototype.getPixelLength = function() {
  1734 this._onScrollListeners=null;
  4282     return this._orientation == Timeline.HORIZONTAL ?
  1735 this._syncWithBandHandler=null;
  4283         this._containerDiv.offsetWidth : this._containerDiv.offsetHeight;
  1736 this._selectorListener=null;
  4284 };
  1737 this._div=null;
  4285 
  1738 this._innerDiv=null;
  4286 Timeline._Impl.prototype.getPixelWidth = function() {
  1739 this._keyboardInput=null;
  4287     return this._orientation == Timeline.VERTICAL ?
  1740 };
  4288         this._containerDiv.offsetWidth : this._containerDiv.offsetHeight;
  1741 Timeline._Band.prototype.addOnScrollListener=function(A){this._onScrollListeners.push(A);
  4289 };
  1742 };
  4290 
  1743 Timeline._Band.prototype.removeOnScrollListener=function(B){for(var A=0;
  4291 Timeline._Impl.prototype.getUnit = function() {
  1744 A<this._onScrollListeners.length;
  4292     return this._unit;
  1745 A++){if(this._onScrollListeners[A]==B){this._onScrollListeners.splice(A,1);
  4293 };
  1746 break;
  4294 
  1747 }}};
  4295 Timeline._Impl.prototype.getWidthStyle = function() {
  1748 Timeline._Band.prototype.setSyncWithBand=function(B,A){if(this._syncWithBand){this._syncWithBand.removeOnScrollListener(this._syncWithBandHandler);
  4296     // which element.style attribute should be changed to affect Timeline's "width"
  1749 }this._syncWithBand=B;
  4297     return this._orientation == Timeline.HORIZONTAL ? 'height' : 'width';
  1750 this._syncWithBand.addOnScrollListener(this._syncWithBandHandler);
  4298 };
  1751 this._highlight=A;
  4299 
  1752 this._positionHighlight();
  4300 Timeline._Impl.prototype.loadXML = function(url, f) {
  1753 };
  4301     var tl = this;
  1754 Timeline._Band.prototype.getLocale=function(){return this._locale;
  4302 
  1755 };
  4303 
  1756 Timeline._Band.prototype.getTimeZone=function(){return this._timeZone;
  4304     var fError = function(statusText, status, xmlhttp) {
  1757 };
  4305         alert("Failed to load data xml from " + url + "\n" + statusText);
  1758 Timeline._Band.prototype.getLabeller=function(){return this._labeller;
  4306         tl.hideLoadingMessage();
  1759 };
  4307     };
  1760 Timeline._Band.prototype.getIndex=function(){return this._index;
  4308     var fDone = function(xmlhttp) {
  1761 };
  4309         try {
  1762 Timeline._Band.prototype.getEther=function(){return this._ether;
  4310             var xml = xmlhttp.responseXML;
  1763 };
  4311             if (!xml.documentElement && xmlhttp.responseStream) {
  1764 Timeline._Band.prototype.getEtherPainter=function(){return this._etherPainter;
  4312                 xml.load(xmlhttp.responseStream);
  1765 };
  4313             }
  1766 Timeline._Band.prototype.getEventSource=function(){return this._eventSource;
  4314             f(xml, url);
  1767 };
  4315         } finally {
  1768 Timeline._Band.prototype.getEventPainter=function(){return this._eventPainter;
  4316             tl.hideLoadingMessage();
  1769 };
  4317         }
  1770 Timeline._Band.prototype.getTimeline=function(){return this._timeline;
  4318     };
  1771 };
  4319 
  1772 Timeline._Band.prototype.updateEventTrackInfo=function(B,A){this._eventTrackIncrement=A;
  4320     this.showLoadingMessage();
  1773 if(B>this._eventTracksNeeded){this._eventTracksNeeded=B;
  4321     window.setTimeout(function() { SimileAjax.XmlHttp.get(url, fError, fDone); }, 0);
  1774 }};
  4322 };
  1775 Timeline._Band.prototype.checkAutoWidth=function(){if(!this._timeline.autoWidth){return ;
  4323 
  1776 }var A=this._eventPainter.getType()=="overview";
  4324 Timeline._Impl.prototype.loadJSON = function(url, f) {
  1777 var C=A?this._theme.event.overviewTrack.autoWidthMargin:this._theme.event.track.autoWidthMargin;
  4325     var tl = this;
  1778 var B=Math.ceil((this._eventTracksNeeded+C)*this._eventTrackIncrement);
  4326 
  1779 B+=A?this._theme.event.overviewTrack.offset:this._theme.event.track.offset;
  4327     var fError = function(statusText, status, xmlhttp) {
  1780 var D=this._bandInfo;
  4328         alert("Failed to load json data from " + url + "\n" + statusText);
  1781 if(B!=D.width){D.width=B;
  4329         tl.hideLoadingMessage();
  1782 }};
  4330     };
  1783 Timeline._Band.prototype.layout=function(){this.paint();
  4331     var fDone = function(xmlhttp) {
  1784 };
  4332         try {
  1785 Timeline._Band.prototype.paint=function(){this._etherPainter.paint();
  4333             f(eval('(' + xmlhttp.responseText + ')'), url);
  1786 this._paintDecorators();
  4334         } finally {
  1787 this._paintEvents();
  4335             tl.hideLoadingMessage();
  1788 };
  4336         }
  1789 Timeline._Band.prototype.softLayout=function(){this.softPaint();
  4337     };
  1790 };
  4338 
  1791 Timeline._Band.prototype.softPaint=function(){this._etherPainter.softPaint();
  4339     this.showLoadingMessage();
  1792 this._softPaintDecorators();
  4340     window.setTimeout(function() { SimileAjax.XmlHttp.get(url, fError, fDone); }, 0);
  1793 this._softPaintEvents();
  4341 };
  1794 };
  4342 
  1795 Timeline._Band.prototype.setBandShiftAndWidth=function(A,D){var C=this._keyboardInput.parentNode;
  4343 
  1796 var B=A+Math.floor(D/2);
  4344 //
  1797 if(this._timeline.isHorizontal()){this._div.style.top=A+"px";
  4345 // Private functions used by Timeline object functions
  1798 this._div.style.height=D+"px";
  4346 //
  1799 C.style.top=B+"px";
  4347 
  1800 C.style.left="-1em";
  4348 Timeline._Impl.prototype._autoWidthScrollListener = function(band) {
  1801 }else{this._div.style.left=A+"px";
  4349     band.getTimeline()._autoWidthCheck(false);
  1802 this._div.style.width=D+"px";
  4350 };
  1803 C.style.left=B+"px";
  4351 
  1804 C.style.top="-1em";
  4352 // called to re-calculate auto width and adjust the overall Timeline div if needed
  1805 }};
  4353 Timeline._Impl.prototype._autoWidthCheck = function(okToShrink) {
  1806 Timeline._Band.prototype.getViewWidth=function(){if(this._timeline.isHorizontal()){return this._div.offsetHeight;
  4354     var timeline = this; // this Timeline
  1807 }else{return this._div.offsetWidth;
  4355     var immediateChange = timeline._starting;
  1808 }};
  4356     var newWidth = 0;
  1809 Timeline._Band.prototype.setViewLength=function(A){this._viewLength=A;
  4357 
  1810 this._recenterDiv();
  4358     function changeTimelineWidth() {
  1811 this._onChanging();
  4359         var widthStyle = timeline.getWidthStyle();
  1812 };
  4360         if (immediateChange) {
  1813 Timeline._Band.prototype.getViewLength=function(){return this._viewLength;
  4361             timeline._containerDiv.style[widthStyle] = newWidth + 'px';
  1814 };
  4362         } else {
  1815 Timeline._Band.prototype.getTotalViewLength=function(){return Timeline._Band.SCROLL_MULTIPLES*this._viewLength;
  4363         	  // animate change
  1816 };
  4364         	  timeline._autoResizing = true;
  1817 Timeline._Band.prototype.getViewOffset=function(){return this._viewOffset;
  4365         	  var animateParam ={};
  1818 };
  4366         	  animateParam[widthStyle] = newWidth + 'px';
  1819 Timeline._Band.prototype.getMinDate=function(){return this._ether.pixelOffsetToDate(this._viewOffset);
  4367 
  1820 };
  4368         	  SimileAjax.jQuery(timeline._containerDiv).animate(
  1821 Timeline._Band.prototype.getMaxDate=function(){return this._ether.pixelOffsetToDate(this._viewOffset+Timeline._Band.SCROLL_MULTIPLES*this._viewLength);
  4369         	      animateParam, timeline.autoWidthAnimationTime,
  1822 };
  4370         	      'linear', function(){timeline._autoResizing = false;});
  1823 Timeline._Band.prototype.getMinVisibleDate=function(){return this._ether.pixelOffsetToDate(0);
  4371         }
  1824 };
  4372     }
  1825 Timeline._Band.prototype.getMaxVisibleDate=function(){return this._ether.pixelOffsetToDate(this._viewLength);
  4373 
  1826 };
  4374     function checkTimelineWidth() {
  1827 Timeline._Band.prototype.getCenterVisibleDate=function(){return this._ether.pixelOffsetToDate(this._viewLength/2);
  4375         var targetWidth = 0; // the new desired width
  1828 };
  4376         var currentWidth = timeline.getPixelWidth();
  1829 Timeline._Band.prototype.setMinVisibleDate=function(A){if(!this._changing){this._moveEther(Math.round(-this._ether.dateToPixelOffset(A)));
  4377 
  1830 }};
  4378         if (timeline._autoResizing) {
  1831 Timeline._Band.prototype.setMaxVisibleDate=function(A){if(!this._changing){this._moveEther(Math.round(this._viewLength-this._ether.dateToPixelOffset(A)));
  4379         	return; // early return
  1832 }};
  4380         }
  1833 Timeline._Band.prototype.setCenterVisibleDate=function(A){if(!this._changing){this._moveEther(Math.round(this._viewLength/2-this._ether.dateToPixelOffset(A)));
  4381 
  1834 }};
  4382         // compute targetWidth
  1835 Timeline._Band.prototype.dateToPixelOffset=function(A){return this._ether.dateToPixelOffset(A)-this._viewOffset;
  4383         for (var i = 0; i < timeline._bands.length; i++) {
  1836 };
  4384             timeline._bands[i].checkAutoWidth();
  1837 Timeline._Band.prototype.pixelOffsetToDate=function(A){return this._ether.pixelOffsetToDate(A+this._viewOffset);
  4385             targetWidth += timeline._bandInfos[i].width;
  1838 };
  4386         }
  1839 Timeline._Band.prototype.createLayerDiv=function(D,B){var C=this._timeline.getDocument().createElement("div");
  4387 
  1840 C.className="timeline-band-layer"+(typeof B=="string"?(" "+B):"");
  4388         if (targetWidth > currentWidth || okToShrink) {
  1841 C.style.zIndex=D;
  4389             // yes, let's change the size
  1842 this._innerDiv.appendChild(C);
  4390             newWidth = targetWidth;
  1843 var A=this._timeline.getDocument().createElement("div");
  4391             changeTimelineWidth();
  1844 A.className="timeline-band-layer-inner";
  4392             timeline._distributeWidths();
  1845 if(SimileAjax.Platform.browser.isIE){A.style.cursor="move";
  4393         }
  1846 }else{A.style.cursor="-moz-grab";
  4394     }
  1847 }C.appendChild(A);
  4395 
  1848 return A;
  4396     // function's mainline
  1849 };
  4397     if (!timeline.autoWidth) {
  1850 Timeline._Band.prototype.removeLayerDiv=function(A){this._innerDiv.removeChild(A.parentNode);
  4398         return; // early return
  1851 };
  4399     }
  1852 Timeline._Band.prototype.scrollToCenter=function(B,C){var A=this._ether.dateToPixelOffset(B);
  4400 
  1853 if(A<-this._viewLength/2){this.setCenterVisibleDate(this.pixelOffsetToDate(A+this._viewLength));
  4401     checkTimelineWidth();
  1854 }else{if(A>3*this._viewLength/2){this.setCenterVisibleDate(this.pixelOffsetToDate(A-this._viewLength));
  4402 };
  1855 }}this._autoScroll(Math.round(this._viewLength/2-this._ether.dateToPixelOffset(B)),C);
  4403 
  1856 };
  4404 Timeline._Impl.prototype._initialize = function() {
  1857 Timeline._Band.prototype.showBubbleForEvent=function(C){var A=this.getEventSource().getEvent(C);
  4405     var containerDiv = this._containerDiv;
  1858 if(A){var B=this;
  4406     var doc = containerDiv.ownerDocument;
  1859 this.scrollToCenter(A.getStart(),function(){B._eventPainter.showBubble(A);
  4407 
  1860 });
  4408     containerDiv.className =
  1861 }};
  4409         containerDiv.className.split(" ").concat("timeline-container").join(" ");
  1862 Timeline._Band.prototype.zoom=function(F,A,E,C){if(!this._zoomSteps){return ;
  4410 
  1863 }A+=this._viewOffset;
  4411 	/*
  1864 var D=this._ether.pixelOffsetToDate(A);
  4412 	 * Set css-class on container div that will define orientation
  1865 var B=this._ether.zoom(F);
  4413 	 */
  1866 this._etherPainter.zoom(B);
  4414 	var orientation = (this.isHorizontal()) ? 'horizontal' : 'vertical'
  1867 this._moveEther(Math.round(-this._ether.dateToPixelOffset(D)));
  4415 	containerDiv.className +=' timeline-'+orientation;
  1868 this._moveEther(A);
  4416 
  1869 };
  4417 
  1870 Timeline._Band.prototype._onMouseDown=function(B,A,C){this.closeBubble();
  4418     while (containerDiv.firstChild) {
  1871 this._dragging=true;
  4419         containerDiv.removeChild(containerDiv.firstChild);
  1872 this._dragX=A.clientX;
  4420     }
  1873 this._dragY=A.clientY;
  4421 
  1874 };
  4422     /*
  1875 Timeline._Band.prototype._onMouseMove=function(D,A,E){if(this._dragging){var C=A.clientX-this._dragX;
  4423      *  inserting copyright and link to simile
  1876 var B=A.clientY-this._dragY;
  4424      */
  1877 this._dragX=A.clientX;
  4425     var elmtCopyright = SimileAjax.Graphics.createTranslucentImage(Timeline.urlPrefix + (this.isHorizontal() ? "images/copyright-vertical.png" : "images/copyright.png"));
  1878 this._dragY=A.clientY;
  4426     elmtCopyright.className = "timeline-copyright";
  1879 this._moveEther(this._timeline.isHorizontal()?C:B);
  4427     elmtCopyright.title = "Timeline copyright SIMILE - www.code.google.com/p/simile-widgets/";
  1880 this._positionHighlight();
  4428     SimileAjax.DOM.registerEvent(elmtCopyright, "click", function() { window.location = "http://www.simile-widgets.org/"; });
  1881 }};
  4429     containerDiv.appendChild(elmtCopyright);
  1882 Timeline._Band.prototype._onMouseUp=function(B,A,C){this._dragging=false;
  4430 
  1883 this._keyboardInput.focus();
  4431     /*
  1884 };
  4432      *  creating bands
  1885 Timeline._Band.prototype._onMouseOut=function(B,A,D){var C=SimileAjax.DOM.getEventRelativeCoordinates(A,B);
  4433      */
  1886 C.x+=this._viewOffset;
  4434     this._bands = [];
  1887 if(C.x<0||C.x>B.offsetWidth||C.y<0||C.y>B.offsetHeight){this._dragging=false;
  4435     for (var i = 0; i < this._bandInfos.length; i++) {
  1888 }};
  4436         var bandInfo = this._bandInfos[i];
  1889 Timeline._Band.prototype._onMouseScroll=function(G,I,E){var A=new Date();
  4437         var bandClass = bandInfo.bandClass || Timeline._Band;
  1890 A=A.getTime();
  4438         var band = new bandClass(this, this._bandInfos[i], i);
  1891 if(!this._lastScrollTime||((A-this._lastScrollTime)>50)){this._lastScrollTime=A;
  4439         this._bands.push(band);
  1892 var H=0;
  4440     }
  1893 if(I.wheelDelta){H=I.wheelDelta/120;
  4441     this._distributeWidths();
  1894 }else{if(I.detail){H=-I.detail/3;
  4442 
  1895 }}var F=this._theme.mouseWheel;
  4443     /*
  1896 if(this._zoomSteps||F==="zoom"){var D=SimileAjax.DOM.getEventRelativeCoordinates(I,G);
  4444      *  sync'ing bands
  1897 if(H!=0){var C;
  4445      */
  1898 if(H>0){C=true;
  4446     for (var i = 0; i < this._bandInfos.length; i++) {
  1899 }if(H<0){C=false;
  4447         var bandInfo = this._bandInfos[i];
  1900 }this._timeline.zoom(C,D.x,D.y,G);
  4448         if ("syncWith" in bandInfo) {
  1901 }}else{if(F==="scroll"){var B=50*(H<0?-1:1);
  4449             this._bands[i].setSyncWithBand(
  1902 this._moveEther(B);
  4450                 this._bands[bandInfo.syncWith],
  1903 }}}if(I.stopPropagation){I.stopPropagation();
  4451                 ("highlight" in bandInfo) ? bandInfo.highlight : false
  1904 }I.cancelBubble=true;
  4452             );
  1905 if(I.preventDefault){I.preventDefault();
  4453         }
  1906 }I.returnValue=false;
  4454     }
  1907 };
  4455 
  1908 Timeline._Band.prototype._onDblClick=function(B,A,D){var C=SimileAjax.DOM.getEventRelativeCoordinates(A,B);
  4456 
  1909 var E=C.x-(this._viewLength/2-this._viewOffset);
  4457     if (this.autoWidth) {
  1910 this._autoScroll(-E);
  4458         for (var i = 0; i < this._bands.length; i++) {
  1911 };
  4459             this._bands[i].addOnScrollListener(this._autoWidthScrollListener);
  1912 Timeline._Band.prototype._onKeyDown=function(B,A,C){if(!this._dragging){switch(A.keyCode){case 27:break;
  4460         }
  1913 case 37:case 38:this._scrollSpeed=Math.min(50,Math.abs(this._scrollSpeed*1.05));
  4461     }
  1914 this._moveEther(this._scrollSpeed);
  4462 
  1915 break;
  4463 
  1916 case 39:case 40:this._scrollSpeed=-Math.min(50,Math.abs(this._scrollSpeed*1.05));
  4464     /*
  1917 this._moveEther(this._scrollSpeed);
  4465      *  creating loading UI
  1918 break;
  4466      */
  1919 default:return true;
  4467     var message = SimileAjax.Graphics.createMessageBubble(doc);
  1920 }this.closeBubble();
  4468     message.containerDiv.className = "timeline-message-container";
  1921 SimileAjax.DOM.cancelEvent(A);
  4469     containerDiv.appendChild(message.containerDiv);
  1922 return false;
  4470 
  1923 }return true;
  4471     message.contentDiv.className = "timeline-message";
  1924 };
  4472     message.contentDiv.innerHTML = "<img src='" + Timeline.urlPrefix + "images/progress-running.gif' /> Loading...";
  1925 Timeline._Band.prototype._onKeyUp=function(B,A,C){if(!this._dragging){this._scrollSpeed=this._originalScrollSpeed;
  4473 
  1926 switch(A.keyCode){case 35:this.setCenterVisibleDate(this._eventSource.getLatestDate());
  4474     this.showLoadingMessage = function() { message.containerDiv.style.display = "block"; };
  1927 break;
  4475     this.hideLoadingMessage = function() { message.containerDiv.style.display = "none"; };
  1928 case 36:this.setCenterVisibleDate(this._eventSource.getEarliestDate());
  4476 };
  1929 break;
  4477 
  1930 case 33:this._autoScroll(this._timeline.getPixelLength());
  4478 Timeline._Impl.prototype._distributeWidths = function() {
  1931 break;
  4479     var length = this.getPixelLength();
  1932 case 34:this._autoScroll(-this._timeline.getPixelLength());
  4480     var width = this.getPixelWidth();
  1933 break;
  4481     var cumulativeWidth = 0;
  1934 default:return true;
  4482 
  1935 }this.closeBubble();
  4483     for (var i = 0; i < this._bands.length; i++) {
  1936 SimileAjax.DOM.cancelEvent(A);
  4484         var band = this._bands[i];
  1937 return false;
  4485         var bandInfos = this._bandInfos[i];
  1938 }return true;
  4486         var widthString = bandInfos.width;
  1939 };
  4487         var bandWidth;
  1940 Timeline._Band.prototype._autoScroll=function(D,C){var A=this;
  4488 
  1941 var B=SimileAjax.Graphics.createAnimation(function(E,F){A._moveEther(F);
  4489         if (typeof widthString == 'string') {
  1942 },0,D,1000,C);
  4490           var x =  widthString.indexOf("%");
  1943 B.run();
  4491           if (x > 0) {
  1944 };
  4492               var percent = parseInt(widthString.substr(0, x));
  1945 Timeline._Band.prototype._moveEther=function(A){this.closeBubble();
  4493               bandWidth = Math.round(percent * width / 100);
  1946 this._viewOffset+=A;
  4494           } else {
  1947 this._ether.shiftPixels(-A);
  4495               bandWidth = parseInt(widthString);
  1948 if(this._timeline.isHorizontal()){this._div.style.left=this._viewOffset+"px";
  4496           }
  1949 }else{this._div.style.top=this._viewOffset+"px";
  4497         } else {
  1950 }if(this._viewOffset>-this._viewLength*0.5||this._viewOffset<-this._viewLength*(Timeline._Band.SCROLL_MULTIPLES-1.5)){this._recenterDiv();
  4498         	// was given an integer
  1951 }else{this.softLayout();
  4499         	bandWidth = widthString;
  1952 }this._onChanging();
  4500         }
  1953 };
  4501 
  1954 Timeline._Band.prototype._onChanging=function(){this._changing=true;
  4502         band.setBandShiftAndWidth(cumulativeWidth, bandWidth);
  1955 this._fireOnScroll();
  4503         band.setViewLength(length);
  1956 this._setSyncWithBandDate();
  4504 
  1957 this._changing=false;
  4505         cumulativeWidth += bandWidth;
  1958 };
  4506     }
  1959 Timeline._Band.prototype._fireOnScroll=function(){for(var A=0;
  4507 };
  1960 A<this._onScrollListeners.length;
  4508 
  1961 A++){this._onScrollListeners[A](this);
  4509 Timeline._Impl.prototype.shiftOK = function(index, shift) {
  1962 }};
  4510     // Returns true if the proposed shift is ok
  1963 Timeline._Band.prototype._setSyncWithBandDate=function(){if(this._syncWithBand){var A=this._ether.pixelOffsetToDate(this.getViewLength()/2);
  4511     //
  1964 this._syncWithBand.setCenterVisibleDate(A);
  4512     // Positive shift means going back in time
  1965 }};
  4513     var going_back = shift > 0,
  1966 Timeline._Band.prototype._onHighlightBandScroll=function(){if(this._syncWithBand){var A=this._syncWithBand.getCenterVisibleDate();
  4514         going_forward = shift < 0;
  1967 var B=this._ether.dateToPixelOffset(A);
  4515 
  1968 this._moveEther(Math.round(this._viewLength/2-B));
  4516     // Is there an edge?
  1969 if(this._highlight){this._etherPainter.setHighlight(this._syncWithBand.getMinVisibleDate(),this._syncWithBand.getMaxVisibleDate());
  4517     if ((going_back    && this.timeline_start == null) ||
  1970 }}};
  4518         (going_forward && this.timeline_stop  == null) ||
  1971 Timeline._Band.prototype._onAddMany=function(){this._paintEvents();
  4519         (shift == 0)) {
  1972 };
  4520         return (true);  // early return
  1973 Timeline._Band.prototype._onClear=function(){this._paintEvents();
  4521     }
  1974 };
  4522 
  1975 Timeline._Band.prototype._positionHighlight=function(){if(this._syncWithBand){var A=this._syncWithBand.getMinVisibleDate();
  4523     // If any of the bands has noted that it is changing the others,
  1976 var B=this._syncWithBand.getMaxVisibleDate();
  4524     // then this shift is a secondary shift in reaction to the real shift,
  1977 if(this._highlight){this._etherPainter.setHighlight(A,B);
  4525     // which already happened. In such cases, ignore it. (The issue is
  1978 }}};
  4526     // that a positive original shift can cause a negative secondary shift,
  1979 Timeline._Band.prototype._recenterDiv=function(){this._viewOffset=-this._viewLength*(Timeline._Band.SCROLL_MULTIPLES-1)/2;
  4527     // as the bands adjust.)
  1980 if(this._timeline.isHorizontal()){this._div.style.left=this._viewOffset+"px";
  4528     var secondary_shift = false;
  1981 this._div.style.width=(Timeline._Band.SCROLL_MULTIPLES*this._viewLength)+"px";
  4529     for (var i = 0; i < this._bands.length && !secondary_shift; i++) {
  1982 }else{this._div.style.top=this._viewOffset+"px";
  4530        secondary_shift = this._bands[i].busy();
  1983 this._div.style.height=(Timeline._Band.SCROLL_MULTIPLES*this._viewLength)+"px";
  4531     }
  1984 }this.layout();
  4532     if (secondary_shift) {
  1985 };
  4533         return(true); // early return
  1986 Timeline._Band.prototype._paintEvents=function(){this._eventPainter.paint();
  4534     }
  1987 };
  4535 
  1988 Timeline._Band.prototype._softPaintEvents=function(){this._eventPainter.softPaint();
  4536     // If we are already at an edge, then don't even think about going any further
  1989 };
  4537     if ((going_back    && this.timeline_at_start) ||
  1990 Timeline._Band.prototype._paintDecorators=function(){for(var A=0;
  4538         (going_forward && this.timeline_at_stop)) {
  1991 A<this._decorators.length;
  4539         return (false);  // early return
  1992 A++){this._decorators[A].paint();
  4540     }
  1993 }};
  4541 
  1994 Timeline._Band.prototype._softPaintDecorators=function(){for(var A=0;
  4542     // Need to check all the bands
  1995 A<this._decorators.length;
  4543     var ok = false; // return value
  1996 A++){this._decorators[A].softPaint();
  4544     // If any of the bands will be or are showing an ok date, then let the shift proceed.
  1997 }};
  4545     for (var i = 0; i < this._bands.length && !ok; i++) {
  1998 Timeline._Band.prototype.closeBubble=function(){SimileAjax.WindowManager.cancelPopups();
  4546        var band = this._bands[i];
  1999 };
  4547        if (going_back) {
  2000 
  4548            ok = (i == index ? band.getMinVisibleDateAfterDelta(shift) : band.getMinVisibleDate())
  2001 
  4549                 >= this.timeline_start;
  2002 /* decorators.js */
  4550        } else {
  2003 Timeline.SpanHighlightDecorator=function(A){this._unit=("unit" in A)?A.unit:SimileAjax.NativeDateUnit;
  4551            ok = (i == index ? band.getMaxVisibleDateAfterDelta(shift) : band.getMaxVisibleDate())
  2004 this._startDate=(typeof A.startDate=="string")?this._unit.parseFromObject(A.startDate):A.startDate;
  4552                 <= this.timeline_stop;
  2005 this._endDate=(typeof A.endDate=="string")?this._unit.parseFromObject(A.endDate):A.endDate;
  4553        }
  2006 this._startLabel=A.startLabel;
  4554     }
  2007 this._endLabel=A.endLabel;
  4555 
  2008 this._color=A.color;
  4556     // process results
  2009 this._cssClass=("cssClass" in A)?A.cssClass:null;
  4557     if (going_back) {
  2010 this._opacity=("opacity" in A)?A.opacity:100;
  4558        this.timeline_at_start = !ok;
  2011 };
  4559        this.timeline_at_stop = false;
  2012 Timeline.SpanHighlightDecorator.prototype.initialize=function(B,A){this._band=B;
  4560     } else {
  2013 this._timeline=A;
  4561        this.timeline_at_stop = !ok;
  2014 this._layerDiv=null;
  4562        this.timeline_at_start = false;
  2015 };
  4563     }
  2016 Timeline.SpanHighlightDecorator.prototype.paint=function(){if(this._layerDiv!=null){this._band.removeLayerDiv(this._layerDiv);
  4564     // This is where you could have an effect once per hitting an
  2017 }this._layerDiv=this._band.createLayerDiv(10);
  4565     // edge of the Timeline. Eg jitter the Timeline
  2018 this._layerDiv.setAttribute("name","span-highlight-decorator");
  4566     //if (!ok) {
  2019 this._layerDiv.style.display="none";
  4567         //alert(going_back ? "At beginning" : "At end");
  2020 var F=this._band.getMinDate();
  4568     //}
  2021 var C=this._band.getMaxDate();
  4569     return (ok);
  2022 if(this._unit.compare(this._startDate,C)<0&&this._unit.compare(this._endDate,F)>0){F=this._unit.later(F,this._startDate);
  4570 };
  2023 C=this._unit.earlier(C,this._endDate);
  4571 
  2024 var D=this._band.dateToPixelOffset(F);
  4572 Timeline._Impl.prototype.zoom = function (zoomIn, x, y, target) {
  2025 var K=this._band.dateToPixelOffset(C);
  4573   var matcher = new RegExp("^timeline-band-([0-9]+)$");
  2026 var I=this._timeline.getDocument();
  4574   var bandIndex = null;
  2027 var H=function(){var L=I.createElement("table");
  4575 
  2028 L.insertRow(0).insertCell(0);
  4576   var result = matcher.exec(target.id);
  2029 return L;
  4577   if (result) {
  2030 };
  4578     bandIndex = parseInt(result[1]);
  2031 var B=I.createElement("div");
  4579   }
  2032 B.className="timeline-highlight-decorator";
  4580 
  2033 if(this._cssClass){B.className+=" "+this._cssClass;
  4581   if (bandIndex != null) {
  2034 }if(this._opacity<100){SimileAjax.Graphics.setOpacity(B,this._opacity);
  4582     this._bands[bandIndex].zoom(zoomIn, x, y, target);
  2035 }this._layerDiv.appendChild(B);
  4583   }
  2036 var J=H();
  4584 
  2037 J.className="timeline-highlight-label timeline-highlight-label-start";
  4585   this.paint();
  2038 var G=J.rows[0].cells[0];
  4586 };
  2039 G.innerHTML=this._startLabel;
  4587 
  2040 if(this._cssClass){G.className="label_"+this._cssClass;
  4588 /*=================================================
  2041 }this._layerDiv.appendChild(J);
  4589  *
  2042 var A=H();
  4590  * Coding standards:
  2043 A.className="timeline-highlight-label timeline-highlight-label-end";
  4591  *
  2044 var E=A.rows[0].cells[0];
  4592  * We aim towards Douglas Crockford's Javascript conventions.
  2045 E.innerHTML=this._endLabel;
  4593  * See:  http://javascript.crockford.com/code.html
  2046 if(this._cssClass){E.className="label_"+this._cssClass;
  4594  * See also: http://www.crockford.com/javascript/javascript.html
  2047 }this._layerDiv.appendChild(A);
  4595  *
  2048 if(this._timeline.isHorizontal()){B.style.left=D+"px";
  4596  * That said, this JS code was written before some recent JS
  2049 B.style.width=(K-D)+"px";
  4597  * support libraries became widely used or available.
  2050 J.style.right=(this._band.getTotalViewLength()-D)+"px";
  4598  * In particular, the _ character is used to indicate a class function or
  2051 J.style.width=(this._startLabel.length)+"em";
  4599  * variable that should be considered private to the class.
  2052 A.style.left=K+"px";
  4600  *
  2053 A.style.width=(this._endLabel.length)+"em";
  4601  * The code mostly uses accessor methods for getting/setting the private
  2054 }else{B.style.top=D+"px";
  4602  * class variables.
  2055 B.style.height=(K-D)+"px";
  4603  *
  2056 J.style.bottom=D+"px";
  4604  * Over time, we'd like to formalize the convention by using support libraries
  2057 J.style.height="1.5px";
  4605  * which enforce privacy in objects.
  2058 A.style.top=K+"px";
  4606  *
  2059 A.style.height="1.5px";
  4607  * We also want to use jslint:  http://www.jslint.com/
  2060 }}this._layerDiv.style.display="block";
  4608  *
  2061 };
  4609  *
  2062 Timeline.SpanHighlightDecorator.prototype.softPaint=function(){};
  4610  *==================================================
  2063 Timeline.PointHighlightDecorator=function(A){this._unit=("unit" in A)?A.unit:SimileAjax.NativeDateUnit;
  4611  */
  2064 this._date=(typeof A.date=="string")?this._unit.parseFromObject(A.date):A.date;
  4612 
  2065 this._width=("width" in A)?A.width:10;
  4613 
  2066 this._color=A.color;
  4614 
  2067 this._cssClass=("cssClass" in A)?A.cssClass:"";
  4615 /*==================================================
  2068 this._opacity=("opacity" in A)?A.opacity:100;
  4616  *  Band
  2069 };
  4617  *==================================================
  2070 Timeline.PointHighlightDecorator.prototype.initialize=function(B,A){this._band=B;
  4618  */
  2071 this._timeline=A;
  4619 Timeline._Band = function(timeline, bandInfo, index) {
  2072 this._layerDiv=null;
  4620     // hack for easier subclassing
  2073 };
  4621     if (timeline !== undefined) {
  2074 Timeline.PointHighlightDecorator.prototype.paint=function(){if(this._layerDiv!=null){this._band.removeLayerDiv(this._layerDiv);
  4622         this.initialize(timeline, bandInfo, index);
  2075 }this._layerDiv=this._band.createLayerDiv(10);
  4623     }
  2076 this._layerDiv.setAttribute("name","span-highlight-decorator");
  4624 };
  2077 this._layerDiv.style.display="none";
  4625 
  2078 var C=this._band.getMinDate();
  4626 Timeline._Band.prototype.initialize = function(timeline, bandInfo, index) {
  2079 var E=this._band.getMaxDate();
  4627     // Set up the band's object
  2080 if(this._unit.compare(this._date,E)<0&&this._unit.compare(this._date,C)>0){var B=this._band.dateToPixelOffset(this._date);
  4628 
  2081 var A=B-Math.round(this._width/2);
  4629     // Munge params: If autoWidth is on for the Timeline, then ensure that
  2082 var D=this._timeline.getDocument();
  4630     // bandInfo.width is an integer
  2083 var F=D.createElement("div");
  4631     if (timeline.autoWidth && typeof bandInfo.width == 'string') {
  2084 F.className="timeline-highlight-point-decorator";
  4632         bandInfo.width = bandInfo.width.indexOf("%") > -1 ? 0 : parseInt(bandInfo.width);
  2085 F.className+=" "+this._cssClass;
  4633     }
  2086 if(this._opacity<100){SimileAjax.Graphics.setOpacity(F,this._opacity);
  4634 
  2087 }this._layerDiv.appendChild(F);
  4635     this._timeline = timeline;
  2088 if(this._timeline.isHorizontal()){F.style.left=A+"px";
  4636     this._bandInfo = bandInfo;
  2089 }else{F.style.top=A+"px";
  4637 
  2090 }}this._layerDiv.style.display="block";
  4638     this._index = index;
  2091 };
  4639 
  2092 Timeline.PointHighlightDecorator.prototype.softPaint=function(){};
  4640     this._locale = ("locale" in bandInfo) ? bandInfo.locale : Timeline.getDefaultLocale();
  2093 
  4641     this._timeZone = ("timeZone" in bandInfo) ? bandInfo.timeZone : 0;
  2094 
  4642     this._labeller = ("labeller" in bandInfo) ? bandInfo.labeller :
  2095 /* detailed-painter.js */
  4643         (("createLabeller" in timeline.getUnit()) ?
  2096 Timeline.DetailedEventPainter=function(A){this._params=A;
  4644             timeline.getUnit().createLabeller(this._locale, this._timeZone) :
  2097 this._onSelectListeners=[];
  4645             new Timeline.GregorianDateLabeller(this._locale, this._timeZone));
  2098 this._filterMatcher=null;
  4646     this._theme = bandInfo.theme;
  2099 this._highlightMatcher=null;
  4647     this._zoomIndex = ("zoomIndex" in bandInfo) ? bandInfo.zoomIndex : 0;
  2100 this._frc=null;
  4648     this._zoomSteps = ("zoomSteps" in bandInfo) ? bandInfo.zoomSteps : null;
  2101 this._eventIdToElmt={};
  4649 
  2102 };
  4650     this._dragging = false;
  2103 Timeline.DetailedEventPainter.prototype.initialize=function(B,A){this._band=B;
  4651     this._changing = false;
  2104 this._timeline=A;
  4652     this._originalScrollSpeed = 5; // pixels
  2105 this._backLayer=null;
  4653     this._scrollSpeed = this._originalScrollSpeed;
  2106 this._eventLayer=null;
  4654     this._viewOrthogonalOffset= 0; // vertical offset if the timeline is horizontal, and vice versa
  2107 this._lineLayer=null;
  4655     this._onScrollListeners = [];
  2108 this._highlightLayer=null;
  4656 
  2109 this._eventIdToElmt=null;
  4657     var b = this;
  2110 };
  4658     this._syncWithBand = null;
  2111 Timeline.DetailedEventPainter.prototype.getType=function(){return"detailed";
  4659     this._syncWithBandHandler = function(band) {
  2112 };
  4660         b._onHighlightBandScroll();
  2113 Timeline.DetailedEventPainter.prototype.addOnSelectListener=function(A){this._onSelectListeners.push(A);
  4661     };
  2114 };
  4662     this._selectorListener = function(band) {
  2115 Timeline.DetailedEventPainter.prototype.removeOnSelectListener=function(B){for(var A=0;
  4663         b._onHighlightBandScroll();
  2116 A<this._onSelectListeners.length;
  4664     };
  2117 A++){if(this._onSelectListeners[A]==B){this._onSelectListeners.splice(A,1);
  4665 
  2118 break;
  4666     /*
  2119 }}};
  4667      *  Install a textbox to capture keyboard events
  2120 Timeline.DetailedEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
  4668      */
  2121 };
  4669     var inputDiv = this._timeline.getDocument().createElement("div");
  2122 Timeline.DetailedEventPainter.prototype.setFilterMatcher=function(A){this._filterMatcher=A;
  4670     inputDiv.className = "timeline-band-input";
  2123 };
  4671     this._timeline.addDiv(inputDiv);
  2124 Timeline.DetailedEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
  4672 
  2125 };
  4673     this._keyboardInput = document.createElement("input");
  2126 Timeline.DetailedEventPainter.prototype.setHighlightMatcher=function(A){this._highlightMatcher=A;
  4674     this._keyboardInput.type = "text";
  2127 };
  4675     inputDiv.appendChild(this._keyboardInput);
  2128 Timeline.DetailedEventPainter.prototype.paint=function(){var B=this._band.getEventSource();
  4676     SimileAjax.DOM.registerEventWithObject(this._keyboardInput, "keydown", this, "_onKeyDown");
  2129 if(B==null){return ;
  4677     SimileAjax.DOM.registerEventWithObject(this._keyboardInput, "keyup", this, "_onKeyUp");
  2130 }this._eventIdToElmt={};
  4678 
  2131 this._prepareForPainting();
  4679     /*
  2132 var I=this._params.theme.event;
  4680      *  The band's outer most div that slides with respect to the timeline's div
  2133 var G=Math.max(I.track.height,this._frc.getLineHeight());
  4681      */
  2134 var F={trackOffset:Math.round(this._band.getViewWidth()/2-G/2),trackHeight:G,trackGap:I.track.gap,trackIncrement:G+I.track.gap,icon:I.instant.icon,iconWidth:I.instant.iconWidth,iconHeight:I.instant.iconHeight,labelWidth:I.label.width};
  4682     this._div = this._timeline.getDocument().createElement("div");
  2135 var C=this._band.getMinDate();
  4683     this._div.id = "timeline-band-" + index;
  2136 var A=this._band.getMaxDate();
  4684     this._div.className = "timeline-band timeline-band-" + index;
  2137 var J=(this._filterMatcher!=null)?this._filterMatcher:function(K){return true;
  4685     this._timeline.addDiv(this._div);
  2138 };
  4686 
  2139 var E=(this._highlightMatcher!=null)?this._highlightMatcher:function(K){return -1;
  4687     SimileAjax.DOM.registerEventWithObject(this._div, "mousedown", this, "_onMouseDown");
  2140 };
  4688     SimileAjax.DOM.registerEventWithObject(this._div, "mousemove", this, "_onMouseMove");
  2141 var D=B.getEventReverseIterator(C,A);
  4689     SimileAjax.DOM.registerEventWithObject(this._div, "mouseup", this, "_onMouseUp");
  2142 while(D.hasNext()){var H=D.next();
  4690     SimileAjax.DOM.registerEventWithObject(this._div, "mouseout", this, "_onMouseOut");
  2143 if(J(H)){this.paintEvent(H,F,this._params.theme,E(H));
  4691     SimileAjax.DOM.registerEventWithObject(this._div, "dblclick", this, "_onDblClick");
  2144 }}this._highlightLayer.style.display="block";
  4692 
  2145 this._lineLayer.style.display="block";
  4693     var mouseWheel = this._theme!= null ? this._theme.mouseWheel : 'scroll'; // theme is not always defined
  2146 this._eventLayer.style.display="block";
  4694     if (mouseWheel === 'zoom' || mouseWheel === 'scroll' || this._zoomSteps) {
  2147 this._band.updateEventTrackInfo(this._lowerTracks.length+this._upperTracks.length,F.trackIncrement);
  4695         // capture mouse scroll
  2148 };
  4696         if (SimileAjax.Platform.browser.isFirefox) {
  2149 Timeline.DetailedEventPainter.prototype.softPaint=function(){};
  4697             SimileAjax.DOM.registerEventWithObject(this._div, "DOMMouseScroll", this, "_onMouseScroll");
  2150 Timeline.DetailedEventPainter.prototype._prepareForPainting=function(){var B=this._band;
  4698         } else {
  2151 if(this._backLayer==null){this._backLayer=this._band.createLayerDiv(0,"timeline-band-events");
  4699             SimileAjax.DOM.registerEventWithObject(this._div, "mousewheel", this, "_onMouseScroll");
  2152 this._backLayer.style.visibility="hidden";
  4700         }
  2153 var A=document.createElement("span");
  4701     }
  2154 A.className="timeline-event-label";
  4702 
  2155 this._backLayer.appendChild(A);
  4703     /*
  2156 this._frc=SimileAjax.Graphics.getFontRenderingContext(A);
  4704      *  The inner div that contains layers
  2157 }this._frc.update();
  4705      */
  2158 this._lowerTracks=[];
  4706     this._innerDiv = this._timeline.getDocument().createElement("div");
  2159 this._upperTracks=[];
  4707     this._innerDiv.className = "timeline-band-inner";
  2160 if(this._highlightLayer!=null){B.removeLayerDiv(this._highlightLayer);
  4708     this._div.appendChild(this._innerDiv);
  2161 }this._highlightLayer=B.createLayerDiv(105,"timeline-band-highlights");
  4709 
  2162 this._highlightLayer.style.display="none";
  4710     /*
  2163 if(this._lineLayer!=null){B.removeLayerDiv(this._lineLayer);
  4711      *  Initialize parts of the band
  2164 }this._lineLayer=B.createLayerDiv(110,"timeline-band-lines");
  4712      */
  2165 this._lineLayer.style.display="none";
  4713     this._ether = bandInfo.ether;
  2166 if(this._eventLayer!=null){B.removeLayerDiv(this._eventLayer);
  4714     bandInfo.ether.initialize(this, timeline);
  2167 }this._eventLayer=B.createLayerDiv(110,"timeline-band-events");
  4715 
  2168 this._eventLayer.style.display="none";
  4716     this._etherPainter = bandInfo.etherPainter;
  2169 };
  4717     bandInfo.etherPainter.initialize(this, timeline);
  2170 Timeline.DetailedEventPainter.prototype.paintEvent=function(B,C,D,A){if(B.isInstant()){this.paintInstantEvent(B,C,D,A);
  4718 
  2171 }else{this.paintDurationEvent(B,C,D,A);
  4719     this._eventSource = bandInfo.eventSource;
  2172 }};
  4720     if (this._eventSource) {
  2173 Timeline.DetailedEventPainter.prototype.paintInstantEvent=function(B,C,D,A){if(B.isImprecise()){this.paintImpreciseInstantEvent(B,C,D,A);
  4721         this._eventListener = {
  2174 }else{this.paintPreciseInstantEvent(B,C,D,A);
  4722             onAddMany: function() { b._onAddMany(); },
  2175 }};
  4723             onClear:   function() { b._onClear(); }
  2176 Timeline.DetailedEventPainter.prototype.paintDurationEvent=function(B,C,D,A){if(B.isImprecise()){this.paintImpreciseDurationEvent(B,C,D,A);
  4724         }
  2177 }else{this.paintPreciseDurationEvent(B,C,D,A);
  4725         this._eventSource.addListener(this._eventListener);
  2178 }};
  4726     }
  2179 Timeline.DetailedEventPainter.prototype.paintPreciseInstantEvent=function(K,N,Q,O){var S=this._timeline.getDocument();
  4727 
  2180 var J=K.getText();
  4728     this._eventPainter = bandInfo.eventPainter;
  2181 var E=K.getStart();
  4729     this._eventTracksNeeded = 0;   // set by painter via updateEventTrackInfo
  2182 var C=Math.round(this._band.dateToPixelOffset(E));
  4730     this._eventTrackIncrement = 0;
  2183 var A=Math.round(C+N.iconWidth/2);
  4731     bandInfo.eventPainter.initialize(this, timeline);
  2184 var I=Math.round(C-N.iconWidth/2);
  4732 
  2185 var G=this._frc.computeSize(J);
  4733     this._decorators = ("decorators" in bandInfo) ? bandInfo.decorators : [];
  2186 var D=this._findFreeTrackForSolid(A,C);
  4734     for (var i = 0; i < this._decorators.length; i++) {
  2187 var B=this._paintEventIcon(K,D,I,N,Q);
  4735         this._decorators[i].initialize(this, timeline);
  2188 var T=A+Q.event.label.offsetFromLine;
  4736     }
  2189 var P=D;
  4737 };
  2190 var F=this._getTrackData(D);
  4738 
  2191 if(Math.min(F.solid,F.text)>=T+G.width){F.solid=I;
  4739 Timeline._Band.SCROLL_MULTIPLES = 5;
  2192 F.text=T;
  4740 
  2193 }else{F.solid=I;
  4741 Timeline._Band.prototype.dispose = function() {
  2194 T=C+Q.event.label.offsetFromLine;
  4742     this.closeBubble();
  2195 P=this._findFreeTrackForText(D,T+G.width,function(U){U.line=C-2;
  4743 
  2196 });
  4744     if (this._eventSource) {
  2197 this._getTrackData(P).text=I;
  4745         this._eventSource.removeListener(this._eventListener);
  2198 this._paintEventLine(K,C,D,P,N,Q);
  4746         this._eventListener = null;
  2199 }var R=Math.round(N.trackOffset+P*N.trackIncrement+N.trackHeight/2-G.height/2);
  4747         this._eventSource = null;
  2200 var M=this._paintEventLabel(K,J,T,R,G.width,G.height,Q);
  4748     }
  2201 var L=this;
  4749 
  2202 var H=function(U,V,W){return L._onClickInstantEvent(B.elmt,V,K);
  4750     this._timeline = null;
  2203 };
  4751     this._bandInfo = null;
  2204 SimileAjax.DOM.registerEvent(B.elmt,"mousedown",H);
  4752 
  2205 SimileAjax.DOM.registerEvent(M.elmt,"mousedown",H);
  4753     this._labeller = null;
  2206 this._createHighlightDiv(O,B,Q);
  4754     this._ether = null;
  2207 this._eventIdToElmt[K.getID()]=B.elmt;
  4755     this._etherPainter = null;
  2208 };
  4756     this._eventPainter = null;
  2209 Timeline.DetailedEventPainter.prototype.paintImpreciseInstantEvent=function(N,Q,V,R){var X=this._timeline.getDocument();
  4757     this._decorators = null;
  2210 var M=N.getText();
  4758 
  2211 var H=N.getStart();
  4759     this._onScrollListeners = null;
  2212 var S=N.getEnd();
  4760     this._syncWithBandHandler = null;
  2213 var E=Math.round(this._band.dateToPixelOffset(H));
  4761     this._selectorListener = null;
  2214 var B=Math.round(this._band.dateToPixelOffset(S));
  4762 
  2215 var A=Math.round(E+Q.iconWidth/2);
  4763     this._div = null;
  2216 var L=Math.round(E-Q.iconWidth/2);
  4764     this._innerDiv = null;
  2217 var J=this._frc.computeSize(M);
  4765     this._keyboardInput = null;
  2218 var F=this._findFreeTrackForSolid(B,E);
  4766 };
  2219 var G=this._paintEventTape(N,F,E,B,V.event.instant.impreciseColor,V.event.instant.impreciseOpacity,Q,V);
  4767 
  2220 var C=this._paintEventIcon(N,F,L,Q,V);
  4768 Timeline._Band.prototype.addOnScrollListener = function(listener) {
  2221 var I=this._getTrackData(F);
  4769     this._onScrollListeners.push(listener);
  2222 I.solid=L;
  4770 };
  2223 var W=A+V.event.label.offsetFromLine;
  4771 
  2224 var D=W+J.width;
  4772 Timeline._Band.prototype.removeOnScrollListener = function(listener) {
  2225 var T;
  4773     for (var i = 0; i < this._onScrollListeners.length; i++) {
  2226 if(D<B){T=F;
  4774         if (this._onScrollListeners[i] == listener) {
  2227 }else{W=E+V.event.label.offsetFromLine;
  4775             this._onScrollListeners.splice(i, 1);
  2228 D=W+J.width;
  4776             break;
  2229 T=this._findFreeTrackForText(F,D,function(Y){Y.line=E-2;
  4777         }
  2230 });
  4778     }
  2231 this._getTrackData(T).text=L;
  4779 };
  2232 this._paintEventLine(N,E,F,T,Q,V);
  4780 
  2233 }var U=Math.round(Q.trackOffset+T*Q.trackIncrement+Q.trackHeight/2-J.height/2);
  4781 Timeline._Band.prototype.setSyncWithBand = function(band, highlight) {
  2234 var P=this._paintEventLabel(N,M,W,U,J.width,J.height,V);
  4782     if (this._syncWithBand) {
  2235 var O=this;
  4783         this._syncWithBand.removeOnScrollListener(this._syncWithBandHandler);
  2236 var K=function(Y,Z,a){return O._onClickInstantEvent(C.elmt,Z,N);
  4784     }
  2237 };
  4785 
  2238 SimileAjax.DOM.registerEvent(C.elmt,"mousedown",K);
  4786     this._syncWithBand = band;
  2239 SimileAjax.DOM.registerEvent(G.elmt,"mousedown",K);
  4787     this._syncWithBand.addOnScrollListener(this._syncWithBandHandler);
  2240 SimileAjax.DOM.registerEvent(P.elmt,"mousedown",K);
  4788     this._highlight = highlight;
  2241 this._createHighlightDiv(R,C,V);
  4789     this._positionHighlight();
  2242 this._eventIdToElmt[N.getID()]=C.elmt;
  4790 };
  2243 };
  4791 
  2244 Timeline.DetailedEventPainter.prototype.paintPreciseDurationEvent=function(J,M,S,O){var T=this._timeline.getDocument();
  4792 Timeline._Band.prototype.getLocale = function() {
  2245 var I=J.getText();
  4793     return this._locale;
  2246 var D=J.getStart();
  4794 };
  2247 var P=J.getEnd();
  4795 
  2248 var B=Math.round(this._band.dateToPixelOffset(D));
  4796 Timeline._Band.prototype.getTimeZone = function() {
  2249 var A=Math.round(this._band.dateToPixelOffset(P));
  4797     return this._timeZone;
  2250 var F=this._frc.computeSize(I);
  4798 };
  2251 var E=this._findFreeTrackForSolid(A);
  4799 
  2252 var N=J.getColor();
  4800 Timeline._Band.prototype.getLabeller = function() {
  2253 N=N!=null?N:S.event.duration.color;
  4801     return this._labeller;
  2254 var C=this._paintEventTape(J,E,B,A,N,100,M,S);
  4802 };
  2255 var H=this._getTrackData(E);
  4803 
  2256 H.solid=B;
  4804 Timeline._Band.prototype.getIndex = function() {
  2257 var U=B+S.event.label.offsetFromLine;
  4805     return this._index;
  2258 var Q=this._findFreeTrackForText(E,U+F.width,function(V){V.line=B-2;
  4806 };
  2259 });
  4807 
  2260 this._getTrackData(Q).text=B-2;
  4808 Timeline._Band.prototype.getEther = function() {
  2261 this._paintEventLine(J,B,E,Q,M,S);
  4809     return this._ether;
  2262 var R=Math.round(M.trackOffset+Q*M.trackIncrement+M.trackHeight/2-F.height/2);
  4810 };
  2263 var L=this._paintEventLabel(J,I,U,R,F.width,F.height,S);
  4811 
  2264 var K=this;
  4812 Timeline._Band.prototype.getEtherPainter = function() {
  2265 var G=function(V,W,X){return K._onClickDurationEvent(C.elmt,W,J);
  4813     return this._etherPainter;
  2266 };
  4814 };
  2267 SimileAjax.DOM.registerEvent(C.elmt,"mousedown",G);
  4815 
  2268 SimileAjax.DOM.registerEvent(L.elmt,"mousedown",G);
  4816 Timeline._Band.prototype.getEventSource = function() {
  2269 this._createHighlightDiv(O,C,S);
  4817     return this._eventSource;
  2270 this._eventIdToElmt[J.getID()]=C.elmt;
  4818 };
  2271 };
  4819 
  2272 Timeline.DetailedEventPainter.prototype.paintImpreciseDurationEvent=function(L,P,W,S){var Z=this._timeline.getDocument();
  4820 Timeline._Band.prototype.getEventPainter = function() {
  2273 var K=L.getText();
  4821     return this._eventPainter;
  2274 var D=L.getStart();
  4822 };
  2275 var Q=L.getLatestStart();
  4823 
  2276 var T=L.getEnd();
  4824 Timeline._Band.prototype.getTimeline = function() {
  2277 var X=L.getEarliestEnd();
  4825     return this._timeline;
  2278 var B=Math.round(this._band.dateToPixelOffset(D));
  4826 };
  2279 var F=Math.round(this._band.dateToPixelOffset(Q));
  4827 
  2280 var A=Math.round(this._band.dateToPixelOffset(T));
  4828 // Autowidth support
  2281 var G=Math.round(this._band.dateToPixelOffset(X));
  4829 Timeline._Band.prototype.updateEventTrackInfo = function(tracks, increment) {
  2282 var H=this._frc.computeSize(K);
  4830     this._eventTrackIncrement = increment; // doesn't vary for a specific band
  2283 var E=this._findFreeTrackForSolid(A);
  4831 
  2284 var R=L.getColor();
  4832     if (tracks > this._eventTracksNeeded) {
  2285 R=R!=null?R:W.event.duration.color;
  4833         this._eventTracksNeeded = tracks;
  2286 var O=this._paintEventTape(L,E,B,A,W.event.duration.impreciseColor,W.event.duration.impreciseOpacity,P,W);
  4834     }
  2287 var C=this._paintEventTape(L,E,F,G,R,100,P,W);
  4835 };
  2288 var J=this._getTrackData(E);
  4836 
  2289 J.solid=B;
  4837 // Autowidth support
  2290 var Y=F+W.event.label.offsetFromLine;
  4838 Timeline._Band.prototype.checkAutoWidth = function() {
  2291 var U=this._findFreeTrackForText(E,Y+H.width,function(a){a.line=F-2;
  4839     // if a new (larger) width is needed by the band
  2292 });
  4840     // then: a) updates the band's bandInfo.width
  2293 this._getTrackData(U).text=F-2;
  4841     //
  2294 this._paintEventLine(L,F,E,U,P,W);
  4842     // desiredWidth for the band is
  2295 var V=Math.round(P.trackOffset+U*P.trackIncrement+P.trackHeight/2-H.height/2);
  4843     //   (number of tracks + margin) * track increment
  2296 var N=this._paintEventLabel(L,K,Y,V,H.width,H.height,W);
  4844     if (! this._timeline.autoWidth) {
  2297 var M=this;
  4845       return; // early return
  2298 var I=function(a,b,c){return M._onClickDurationEvent(C.elmt,b,L);
  4846     }
  2299 };
  4847 
  2300 SimileAjax.DOM.registerEvent(C.elmt,"mousedown",I);
  4848     var overviewBand = this._eventPainter.getType() == 'overview';
  2301 SimileAjax.DOM.registerEvent(N.elmt,"mousedown",I);
  4849     var margin = overviewBand ?
  2302 this._createHighlightDiv(S,C,W);
  4850        this._theme.event.overviewTrack.autoWidthMargin :
  2303 this._eventIdToElmt[L.getID()]=C.elmt;
  4851        this._theme.event.track.autoWidthMargin;
  2304 };
  4852     var desiredWidth = Math.ceil((this._eventTracksNeeded + margin) *
  2305 Timeline.DetailedEventPainter.prototype._findFreeTrackForSolid=function(B,A){for(var D=0;
  4853                        this._eventTrackIncrement);
  2306 true;
  4854     // add offset amount (additional margin)
  2307 D++){if(D<this._lowerTracks.length){var C=this._lowerTracks[D];
  4855     desiredWidth += overviewBand ? this._theme.event.overviewTrack.offset :
  2308 if(Math.min(C.solid,C.text)>B&&(!(A)||C.line>A)){return D;
  4856                                    this._theme.event.track.offset;
  2309 }}else{this._lowerTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
  4857     var bandInfo = this._bandInfo;
  2310 return D;
  4858 
  2311 }if(D<this._upperTracks.length){var C=this._upperTracks[D];
  4859     if (desiredWidth != bandInfo.width) {
  2312 if(Math.min(C.solid,C.text)>B&&(!(A)||C.line>A)){return -1-D;
  4860         bandInfo.width = desiredWidth;
  2313 }}else{this._upperTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
  4861     }
  2314 return -1-D;
  4862 };
  2315 }}};
  4863 
  2316 Timeline.DetailedEventPainter.prototype._findFreeTrackForText=function(D,C,H){var F;
  4864 Timeline._Band.prototype.layout = function() {
  2317 var G;
  4865     this.paint();
  2318 var B;
  4866 };
  2319 var J;
  4867 
  2320 if(D<0){F=true;
  4868 Timeline._Band.prototype.paint = function() {
  2321 B=-D;
  4869     this._etherPainter.paint();
  2322 G=this._findFreeUpperTrackForText(B,C);
  4870     this._paintDecorators();
  2323 J=-1-G;
  4871     this._paintEvents();
  2324 }else{if(D>0){F=false;
  4872 };
  2325 B=D+1;
  4873 
  2326 G=this._findFreeLowerTrackForText(B,C);
  4874 Timeline._Band.prototype.softLayout = function() {
  2327 J=G;
  4875     this.softPaint();
  2328 }else{var A=this._findFreeUpperTrackForText(0,C);
  4876 };
  2329 var I=this._findFreeLowerTrackForText(1,C);
  4877 
  2330 if(I-1<=A){F=false;
  4878 Timeline._Band.prototype.softPaint = function() {
  2331 B=1;
  4879     this._etherPainter.softPaint();
  2332 G=I;
  4880     this._softPaintDecorators();
  2333 J=G;
  4881     this._softPaintEvents();
  2334 }else{F=true;
  4882 };
  2335 B=0;
  4883 
  2336 G=A;
  4884 Timeline._Band.prototype.setBandShiftAndWidth = function(shift, width) {
  2337 J=-1-G;
  4885     var inputDiv = this._keyboardInput.parentNode;
  2338 }}}if(F){if(G==this._upperTracks.length){this._upperTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
  4886     var middle = shift + Math.floor(width / 2);
  2339 }for(var E=B;
  4887     if (this._timeline.isHorizontal()) {
  2340 E<G;
  4888         this._div.style.top = shift + "px";
  2341 E++){H(this._upperTracks[E]);
  4889         this._div.style.height = width + "px";
  2342 }}else{if(G==this._lowerTracks.length){this._lowerTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
  4890 
  2343 }for(var E=B;
  4891         inputDiv.style.top = middle + "px";
  2344 E<G;
  4892         inputDiv.style.left = "-1em";
  2345 E++){H(this._lowerTracks[E]);
  4893     } else {
  2346 }}return J;
  4894         this._div.style.left = shift + "px";
  2347 };
  4895         this._div.style.width = width + "px";
  2348 Timeline.DetailedEventPainter.prototype._findFreeLowerTrackForText=function(A,C){for(;
  4896 
  2349 A<this._lowerTracks.length;
  4897         inputDiv.style.left = middle + "px";
  2350 A++){var B=this._lowerTracks[A];
  4898         inputDiv.style.top = "-1em";
  2351 if(Math.min(B.solid,B.text)>=C){break;
  4899     }
  2352 }}return A;
  4900 };
  2353 };
  4901 
  2354 Timeline.DetailedEventPainter.prototype._findFreeUpperTrackForText=function(A,C){for(;
  4902 Timeline._Band.prototype.getViewWidth = function() {
  2355 A<this._upperTracks.length;
  4903     if (this._timeline.isHorizontal()) {
  2356 A++){var B=this._upperTracks[A];
  4904         return this._div.offsetHeight;
  2357 if(Math.min(B.solid,B.text)>=C){break;
  4905     } else {
  2358 }}return A;
  4906         return this._div.offsetWidth;
  2359 };
  4907     }
  2360 Timeline.DetailedEventPainter.prototype._getTrackData=function(A){return(A<0)?this._upperTracks[-A-1]:this._lowerTracks[A];
  4908 };
  2361 };
  4909 
  2362 Timeline.DetailedEventPainter.prototype._paintEventLine=function(I,C,F,A,G,D){var H=Math.round(G.trackOffset+F*G.trackIncrement+G.trackHeight/2);
  4910 Timeline._Band.prototype.setViewLength = function(length) {
  2363 var J=Math.round(Math.abs(A-F)*G.trackIncrement);
  4911     this._viewLength = length;
  2364 var E="1px solid "+D.event.label.lineColor;
  4912     this._recenterDiv();
  2365 var B=this._timeline.getDocument().createElement("div");
  4913     this._onChanging();
  2366 B.style.position="absolute";
  4914 };
  2367 B.style.left=C+"px";
  4915 
  2368 B.style.width=D.event.label.offsetFromLine+"px";
  4916 Timeline._Band.prototype.getViewLength = function() {
  2369 B.style.height=J+"px";
  4917     return this._viewLength;
  2370 if(F>A){B.style.top=(H-J)+"px";
  4918 };
  2371 B.style.borderTop=E;
  4919 
  2372 }else{B.style.top=H+"px";
  4920 Timeline._Band.prototype.getTotalViewLength = function() {
  2373 B.style.borderBottom=E;
  4921     return Timeline._Band.SCROLL_MULTIPLES * this._viewLength;
  2374 }B.style.borderLeft=E;
  4922 };
  2375 this._lineLayer.appendChild(B);
  4923 
  2376 };
  4924 Timeline._Band.prototype.getViewOffset = function() {
  2377 Timeline.DetailedEventPainter.prototype._paintEventIcon=function(I,E,B,F,D){var H=I.getIcon();
  4925     return this._viewOffset;
  2378 H=H!=null?H:F.icon;
  4926 };
  2379 var J=F.trackOffset+E*F.trackIncrement+F.trackHeight/2;
  4927 
  2380 var G=Math.round(J-F.iconHeight/2);
  4928 Timeline._Band.prototype.getMinDate = function() {
  2381 var C=SimileAjax.Graphics.createTranslucentImage(H);
  4929     return this._ether.pixelOffsetToDate(this._viewOffset);
  2382 var A=this._timeline.getDocument().createElement("div");
  4930 };
  2383 A.style.position="absolute";
  4931 
  2384 A.style.left=B+"px";
  4932 Timeline._Band.prototype.getMaxDate = function() {
  2385 A.style.top=G+"px";
  4933     return this._ether.pixelOffsetToDate(this._viewOffset + Timeline._Band.SCROLL_MULTIPLES * this._viewLength);
  2386 A.appendChild(C);
  4934 };
  2387 A.style.cursor="pointer";
  4935 
  2388 if(I._title!=null){A.title=I._title;
  4936 Timeline._Band.prototype.getMinVisibleDate = function() {
  2389 }this._eventLayer.appendChild(A);
  4937     return this._ether.pixelOffsetToDate(0);
  2390 return{left:B,top:G,width:F.iconWidth,height:F.iconHeight,elmt:A};
  4938 };
  2391 };
  4939 
  2392 Timeline.DetailedEventPainter.prototype._paintEventLabel=function(H,I,B,F,A,J,D){var G=this._timeline.getDocument();
  4940 Timeline._Band.prototype.getMinVisibleDateAfterDelta = function(delta) {
  2393 var K=G.createElement("div");
  4941     return this._ether.pixelOffsetToDate(delta);
  2394 K.style.position="absolute";
  4942 };
  2395 K.style.left=B+"px";
  4943 
  2396 K.style.width=A+"px";
  4944 Timeline._Band.prototype.getMaxVisibleDate = function() {
  2397 K.style.top=F+"px";
  4945     // Max date currently visible on band
  2398 K.style.height=J+"px";
  4946     return this._ether.pixelOffsetToDate(this._viewLength);
  2399 K.style.backgroundColor=D.event.label.backgroundColor;
  4947 };
  2400 SimileAjax.Graphics.setOpacity(K,D.event.label.backgroundOpacity);
  4948 
  2401 this._eventLayer.appendChild(K);
  4949 Timeline._Band.prototype.getMaxVisibleDateAfterDelta = function(delta) {
  2402 var E=G.createElement("div");
  4950     // Max date visible on band after delta px view change is applied
  2403 E.style.position="absolute";
  4951     return this._ether.pixelOffsetToDate(this._viewLength + delta);
  2404 E.style.left=B+"px";
  4952 };
  2405 E.style.width=A+"px";
  4953 
  2406 E.style.top=F+"px";
  4954 Timeline._Band.prototype.getCenterVisibleDate = function() {
  2407 E.innerHTML=I;
  4955     return this._ether.pixelOffsetToDate(this._viewLength / 2);
  2408 E.style.cursor="pointer";
  4956 };
  2409 if(H._title!=null){E.title=H._title;
  4957 
  2410 }var C=H.getTextColor();
  4958 Timeline._Band.prototype.setMinVisibleDate = function(date) {
  2411 if(C==null){C=H.getColor();
  4959     if (!this._changing) {
  2412 }if(C!=null){E.style.color=C;
  4960         this._moveEther(Math.round(-this._ether.dateToPixelOffset(date)));
  2413 }this._eventLayer.appendChild(E);
  4961     }
  2414 return{left:B,top:F,width:A,height:J,elmt:E};
  4962 };
  2415 };
  4963 
  2416 Timeline.DetailedEventPainter.prototype._paintEventTape=function(L,H,E,A,C,G,I,F){var B=A-E;
  4964 Timeline._Band.prototype.setMaxVisibleDate = function(date) {
  2417 var D=F.event.tape.height;
  4965     if (!this._changing) {
  2418 var M=I.trackOffset+H*I.trackIncrement+I.trackHeight/2;
  4966         this._moveEther(Math.round(this._viewLength - this._ether.dateToPixelOffset(date)));
  2419 var J=Math.round(M-D/2);
  4967     }
  2420 var K=this._timeline.getDocument().createElement("div");
  4968 };
  2421 K.style.position="absolute";
  4969 
  2422 K.style.left=E+"px";
  4970 Timeline._Band.prototype.setCenterVisibleDate = function(date) {
  2423 K.style.width=B+"px";
  4971     if (!this._changing) {
  2424 K.style.top=J+"px";
  4972         this._moveEther(Math.round(this._viewLength / 2 - this._ether.dateToPixelOffset(date)));
  2425 K.style.height=D+"px";
  4973     }
  2426 K.style.backgroundColor=C;
  4974 };
  2427 K.style.overflow="hidden";
  4975 
  2428 K.style.cursor="pointer";
  4976 Timeline._Band.prototype.dateToPixelOffset = function(date) {
  2429 if(L._title!=null){K.title=L._title;
  4977     return this._ether.dateToPixelOffset(date) - this._viewOffset;
  2430 }SimileAjax.Graphics.setOpacity(K,G);
  4978 };
  2431 this._eventLayer.appendChild(K);
  4979 
  2432 return{left:E,top:J,width:B,height:D,elmt:K};
  4980 Timeline._Band.prototype.pixelOffsetToDate = function(pixels) {
  2433 };
  4981     return this._ether.pixelOffsetToDate(pixels + this._viewOffset);
  2434 Timeline.DetailedEventPainter.prototype._createHighlightDiv=function(A,C,E){if(A>=0){var D=this._timeline.getDocument();
  4982 };
  2435 var G=E.event;
  4983 
  2436 var B=G.highlightColors[Math.min(A,G.highlightColors.length-1)];
  4984 Timeline._Band.prototype.getViewOrthogonalOffset = function() {
  2437 var F=D.createElement("div");
  4985     return this._viewOrthogonalOffset;
  2438 F.style.position="absolute";
  4986 };
  2439 F.style.overflow="hidden";
  4987 
  2440 F.style.left=(C.left-2)+"px";
  4988 Timeline._Band.prototype.setViewOrthogonalOffset = function(offset) {
  2441 F.style.width=(C.width+4)+"px";
  4989     this._viewOrthogonalOffset = Math.max(0, offset);
  2442 F.style.top=(C.top-2)+"px";
  4990 };
  2443 F.style.height=(C.height+4)+"px";
  4991 
  2444 F.style.background=B;
  4992 Timeline._Band.prototype.createLayerDiv = function(zIndex, className) {
  2445 this._highlightLayer.appendChild(F);
  4993     var div = this._timeline.getDocument().createElement("div");
  2446 }};
  4994     div.className = "timeline-band-layer" + (typeof className == "string" ? (" " + className) : "");
  2447 Timeline.DetailedEventPainter.prototype._onClickInstantEvent=function(B,C,A){var D=SimileAjax.DOM.getPageCoordinates(B);
  4995     div.style.zIndex = zIndex;
  2448 this._showBubble(D.left+Math.ceil(B.offsetWidth/2),D.top+Math.ceil(B.offsetHeight/2),A);
  4996     this._innerDiv.appendChild(div);
  2449 this._fireOnSelect(A.getID());
  4997 
  2450 C.cancelBubble=true;
  4998     var innerDiv = this._timeline.getDocument().createElement("div");
  2451 SimileAjax.DOM.cancelEvent(C);
  4999     innerDiv.className = "timeline-band-layer-inner";
  2452 return false;
  5000     if (SimileAjax.Platform.browser.isIE) {
  2453 };
  5001         innerDiv.style.cursor = "move";
  2454 Timeline.DetailedEventPainter.prototype._onClickDurationEvent=function(D,C,B){if("pageX" in C){var A=C.pageX;
  5002     } else {
  2455 var F=C.pageY;
  5003         innerDiv.style.cursor = "-moz-grab";
  2456 }else{var E=SimileAjax.DOM.getPageCoordinates(D);
  5004     }
  2457 var A=C.offsetX+E.left;
  5005     div.appendChild(innerDiv);
  2458 var F=C.offsetY+E.top;
  5006 
  2459 }this._showBubble(A,F,B);
  5007     return innerDiv;
  2460 this._fireOnSelect(B.getID());
  5008 };
  2461 C.cancelBubble=true;
  5009 
  2462 SimileAjax.DOM.cancelEvent(C);
  5010 Timeline._Band.prototype.removeLayerDiv = function(div) {
  2463 return false;
  5011     this._innerDiv.removeChild(div.parentNode);
  2464 };
  5012 };
  2465 Timeline.DetailedEventPainter.prototype.showBubble=function(A){var B=this._eventIdToElmt[A.getID()];
  5013 
  2466 if(B){var C=SimileAjax.DOM.getPageCoordinates(B);
  5014 Timeline._Band.prototype.scrollToCenter = function(date, f) {
  2467 this._showBubble(C.left+B.offsetWidth/2,C.top+B.offsetHeight/2,A);
  5015     var pixelOffset = this._ether.dateToPixelOffset(date);
  2468 }};
  5016     if (pixelOffset < -this._viewLength / 2) {
  2469 Timeline.DetailedEventPainter.prototype._showBubble=function(A,E,B){var D=document.createElement("div");
  5017         this.setCenterVisibleDate(this.pixelOffsetToDate(pixelOffset + this._viewLength));
  2470 var C=this._params.theme.event.bubble;
  5018     } else if (pixelOffset > 3 * this._viewLength / 2) {
  2471 B.fillInfoBubble(D,this._params.theme,this._band.getLabeller());
  5019         this.setCenterVisibleDate(this.pixelOffsetToDate(pixelOffset - this._viewLength));
  2472 SimileAjax.WindowManager.cancelPopups();
  5020     }
  2473 SimileAjax.Graphics.createBubbleForContentAndPoint(D,A,E,C.width,null,C.maxHeight);
  5021     this._autoScroll(Math.round(this._viewLength / 2 - this._ether.dateToPixelOffset(date)), f);
  2474 };
  5022 };
  2475 Timeline.DetailedEventPainter.prototype._fireOnSelect=function(B){for(var A=0;
  5023 
  2476 A<this._onSelectListeners.length;
  5024 Timeline._Band.prototype.showBubbleForEvent = function(eventID) {
  2477 A++){this._onSelectListeners[A](B);
  5025     var evt = this.getEventSource().getEvent(eventID);
  2478 }};
  5026     if (evt) {
  2479 
  5027         var self = this;
  2480 
  5028         this.scrollToCenter(evt.getStart(), function() {
  2481 /* ether-painters.js */
  5029             self._eventPainter.showBubble(evt);
  2482 Timeline.GregorianEtherPainter=function(A){this._params=A;
  5030         });
  2483 this._theme=A.theme;
  5031     }
  2484 this._unit=A.unit;
  5032 };
  2485 this._multiple=("multiple" in A)?A.multiple:1;
  5033 
  2486 };
  5034 Timeline._Band.prototype.zoom = function(zoomIn, x, y, target) {
  2487 Timeline.GregorianEtherPainter.prototype.initialize=function(C,B){this._band=C;
  5035   if (!this._zoomSteps) {
  2488 this._timeline=B;
  5036     // zoom disabled
  2489 this._backgroundLayer=C.createLayerDiv(0);
  5037     return;
  2490 this._backgroundLayer.setAttribute("name","ether-background");
  5038   }
  2491 this._backgroundLayer.className="timeline-ether-bg";
  5039 
  2492 this._markerLayer=null;
  5040   // shift the x value by our offset
  2493 this._lineLayer=null;
  5041   x += this._viewOffset;
  2494 var D=("align" in this._params&&this._params.align!=undefined)?this._params.align:this._theme.ether.interval.marker[B.isHorizontal()?"hAlign":"vAlign"];
  5042 
  2495 var A=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
  5043   var zoomDate = this._ether.pixelOffsetToDate(x);
  2496 this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,D,A);
  5044   var netIntervalChange = this._ether.zoom(zoomIn);
  2497 this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
  5045   this._etherPainter.zoom(netIntervalChange);
  2498 };
  5046 
  2499 Timeline.GregorianEtherPainter.prototype.setHighlight=function(A,B){this._highlight.position(A,B);
  5047   // shift our zoom date to the far left
  2500 };
  5048   this._moveEther(Math.round(-this._ether.dateToPixelOffset(zoomDate)));
  2501 Timeline.GregorianEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
  5049   // then shift it back to where the mouse was
  2502 }this._markerLayer=this._band.createLayerDiv(100);
  5050   this._moveEther(x);
  2503 this._markerLayer.setAttribute("name","ether-markers");
  5051 };
  2504 this._markerLayer.style.display="none";
  5052 
  2505 if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
  5053 Timeline._Band.prototype._onMouseDown = function(innerFrame, evt, target) {
  2506 }this._lineLayer=this._band.createLayerDiv(1);
  5054     this.closeBubble();
  2507 this._lineLayer.setAttribute("name","ether-lines");
  5055 
  2508 this._lineLayer.style.display="none";
  5056     this._dragging = true;
  2509 var C=this._band.getMinDate();
  5057     this._dragX = evt.clientX;
  2510 var F=this._band.getMaxDate();
  5058     this._dragY = evt.clientY;
  2511 var B=this._band.getTimeZone();
  5059 };
  2512 var E=this._band.getLabeller();
  5060 
  2513 SimileAjax.DateTime.roundDownToInterval(C,this._unit,B,this._multiple,this._theme.firstDayOfWeek);
  5061 Timeline._Band.prototype._onMouseMove = function(innerFrame, evt, target) {
  2514 var D=this;
  5062     if (this._dragging) {
  2515 var A=function(G){for(var H=0;
  5063         var diffX = evt.clientX - this._dragX;
  2516 H<D._multiple;
  5064         var diffY = evt.clientY - this._dragY;
  2517 H++){SimileAjax.DateTime.incrementByInterval(G,D._unit);
  5065 
  2518 }};
  5066         this._dragX = evt.clientX;
  2519 while(C.getTime()<F.getTime()){this._intervalMarkerLayout.createIntervalMarker(C,E,this._unit,this._markerLayer,this._lineLayer);
  5067         this._dragY = evt.clientY;
  2520 A(C);
  5068 
  2521 }this._markerLayer.style.display="block";
  5069         if (this._timeline.isHorizontal()) {
  2522 this._lineLayer.style.display="block";
  5070             this._moveEther(diffX, diffY);
  2523 };
  5071         } else {
  2524 Timeline.GregorianEtherPainter.prototype.softPaint=function(){};
  5072             this._moveEther(diffY, diffX);
  2525 Timeline.GregorianEtherPainter.prototype.zoom=function(A){if(A!=0){this._unit+=A;
  5073         }
  2526 }};
  5074         this._positionHighlight();
  2527 Timeline.HotZoneGregorianEtherPainter=function(G){this._params=G;
  5075     }
  2528 this._theme=G.theme;
  5076 };
  2529 this._zones=[{startTime:Number.NEGATIVE_INFINITY,endTime:Number.POSITIVE_INFINITY,unit:G.unit,multiple:1}];
  5077 
  2530 for(var E=0;
  5078 Timeline._Band.prototype._onMouseUp = function(innerFrame, evt, target) {
  2531 E<G.zones.length;
  5079     this._dragging = false;
  2532 E++){var B=G.zones[E];
  5080     this._keyboardInput.focus();
  2533 var D=SimileAjax.DateTime.parseGregorianDateTime(B.start).getTime();
  5081 };
  2534 var F=SimileAjax.DateTime.parseGregorianDateTime(B.end).getTime();
  5082 
  2535 for(var C=0;
  5083 Timeline._Band.prototype._onMouseOut = function(innerFrame, evt, target) {
  2536 C<this._zones.length&&F>D;
  5084     var coords = SimileAjax.DOM.getEventRelativeCoordinates(evt, innerFrame);
  2537 C++){var A=this._zones[C];
  5085     coords.x += this._viewOffset;
  2538 if(D<A.endTime){if(D>A.startTime){this._zones.splice(C,0,{startTime:A.startTime,endTime:D,unit:A.unit,multiple:A.multiple});
  5086     if (coords.x < 0 || coords.x > innerFrame.offsetWidth ||
  2539 C++;
  5087         coords.y < 0 || coords.y > innerFrame.offsetHeight) {
  2540 A.startTime=D;
  5088         this._dragging = false;
  2541 }if(F<A.endTime){this._zones.splice(C,0,{startTime:D,endTime:F,unit:B.unit,multiple:(B.multiple)?B.multiple:1});
  5089     }
  2542 C++;
  5090 };
  2543 A.startTime=F;
  5091 
  2544 D=F;
  5092 Timeline._Band.prototype._onMouseScroll = function(innerFrame, evt, target) {
  2545 }else{A.multiple=B.multiple;
  5093   var now = new Date();
  2546 A.unit=B.unit;
  5094   now = now.getTime();
  2547 D=A.endTime;
  5095 
  2548 }}}}};
  5096   if (!this._lastScrollTime || ((now - this._lastScrollTime) > 50)) {
  2549 Timeline.HotZoneGregorianEtherPainter.prototype.initialize=function(C,B){this._band=C;
  5097     // limit 1 scroll per 200ms due to FF3 sending multiple events back to back
  2550 this._timeline=B;
  5098     this._lastScrollTime = now;
  2551 this._backgroundLayer=C.createLayerDiv(0);
  5099 
  2552 this._backgroundLayer.setAttribute("name","ether-background");
  5100     var delta = 0;
  2553 this._backgroundLayer.className="timeline-ether-bg";
  5101     if (evt.wheelDelta) {
  2554 this._markerLayer=null;
  5102       delta = evt.wheelDelta/120;
  2555 this._lineLayer=null;
  5103     } else if (evt.detail) {
  2556 var D=("align" in this._params&&this._params.align!=undefined)?this._params.align:this._theme.ether.interval.marker[B.isHorizontal()?"hAlign":"vAlign"];
  5104       delta = -evt.detail/3;
  2557 var A=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
  5105     }
  2558 this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,D,A);
  5106 
  2559 this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
  5107     // either scroll or zoom
  2560 };
  5108     var mouseWheel = this._theme.mouseWheel;
  2561 Timeline.HotZoneGregorianEtherPainter.prototype.setHighlight=function(A,B){this._highlight.position(A,B);
  5109 
  2562 };
  5110     if (this._zoomSteps || mouseWheel === 'zoom') {
  2563 Timeline.HotZoneGregorianEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
  5111       var loc = SimileAjax.DOM.getEventRelativeCoordinates(evt, innerFrame);
  2564 }this._markerLayer=this._band.createLayerDiv(100);
  5112       if (delta != 0) {
  2565 this._markerLayer.setAttribute("name","ether-markers");
  5113         var zoomIn;
  2566 this._markerLayer.style.display="none";
  5114         if (delta > 0)
  2567 if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
  5115           zoomIn = true;
  2568 }this._lineLayer=this._band.createLayerDiv(1);
  5116         if (delta < 0)
  2569 this._lineLayer.setAttribute("name","ether-lines");
  5117           zoomIn = false;
  2570 this._lineLayer.style.display="none";
  5118         // call zoom on the timeline so we could zoom multiple bands if desired
  2571 var D=this._band.getMinDate();
  5119         this._timeline.zoom(zoomIn, loc.x, loc.y, innerFrame);
  2572 var A=this._band.getMaxDate();
  5120       }
  2573 var K=this._band.getTimeZone();
  5121     }
  2574 var I=this._band.getLabeller();
  5122     else if (mouseWheel === 'scroll') {
  2575 var B=this;
  5123     	var move_amt = 50 * (delta < 0 ? -1 : 1);
  2576 var L=function(N,M){for(var O=0;
  5124       this._moveEther(move_amt);
  2577 O<M.multiple;
  5125     }
  2578 O++){SimileAjax.DateTime.incrementByInterval(N,M.unit);
  5126   }
  2579 }};
  5127 
  2580 var C=0;
  5128   // prevent bubble
  2581 while(C<this._zones.length){if(D.getTime()<this._zones[C].endTime){break;
  5129   if (evt.stopPropagation) {
  2582 }C++;
  5130     evt.stopPropagation();
  2583 }var E=this._zones.length-1;
  5131   }
  2584 while(E>=0){if(A.getTime()>this._zones[E].startTime){break;
  5132   evt.cancelBubble = true;
  2585 }E--;
  5133 
  2586 }for(var H=C;
  5134   // prevent the default action
  2587 H<=E;
  5135   if (evt.preventDefault) {
  2588 H++){var G=this._zones[H];
  5136     evt.preventDefault();
  2589 var J=new Date(Math.max(D.getTime(),G.startTime));
  5137   }
  2590 var F=new Date(Math.min(A.getTime(),G.endTime));
  5138   evt.returnValue = false;
  2591 SimileAjax.DateTime.roundDownToInterval(J,G.unit,K,G.multiple,this._theme.firstDayOfWeek);
  5139 };
  2592 SimileAjax.DateTime.roundUpToInterval(F,G.unit,K,G.multiple,this._theme.firstDayOfWeek);
  5140 
  2593 while(J.getTime()<F.getTime()){this._intervalMarkerLayout.createIntervalMarker(J,I,G.unit,this._markerLayer,this._lineLayer);
  5141 Timeline._Band.prototype._onDblClick = function(innerFrame, evt, target) {
  2594 L(J,G);
  5142     var coords = SimileAjax.DOM.getEventRelativeCoordinates(evt, innerFrame);
  2595 }}this._markerLayer.style.display="block";
  5143     var distance = coords.x - (this._viewLength / 2 - this._viewOffset);
  2596 this._lineLayer.style.display="block";
  5144 
  2597 };
  5145     this._autoScroll(-distance);
  2598 Timeline.HotZoneGregorianEtherPainter.prototype.softPaint=function(){};
  5146 };
  2599 Timeline.HotZoneGregorianEtherPainter.prototype.zoom=function(B){if(B!=0){for(var A=0;
  5147 
  2600 A<this._zones.length;
  5148 Timeline._Band.prototype._onKeyDown = function(keyboardInput, evt, target) {
  2601 ++A){if(this._zones[A]){this._zones[A].unit+=B;
  5149     if (!this._dragging) {
  2602 }}}};
  5150         switch (evt.keyCode) {
  2603 Timeline.YearCountEtherPainter=function(A){this._params=A;
  5151         case 27: // ESC
  2604 this._theme=A.theme;
  5152             break;
  2605 this._startDate=SimileAjax.DateTime.parseGregorianDateTime(A.startDate);
  5153         case 37: // left arrow
  2606 this._multiple=("multiple" in A)?A.multiple:1;
  5154         case 38: // up arrow
  2607 };
  5155             this._scrollSpeed = Math.min(50, Math.abs(this._scrollSpeed * 1.05));
  2608 Timeline.YearCountEtherPainter.prototype.initialize=function(C,B){this._band=C;
  5156             this._moveEther(this._scrollSpeed);
  2609 this._timeline=B;
  5157             break;
  2610 this._backgroundLayer=C.createLayerDiv(0);
  5158         case 39: // right arrow
  2611 this._backgroundLayer.setAttribute("name","ether-background");
  5159         case 40: // down arrow
  2612 this._backgroundLayer.className="timeline-ether-bg";
  5160             this._scrollSpeed = -Math.min(50, Math.abs(this._scrollSpeed * 1.05));
  2613 this._markerLayer=null;
  5161             this._moveEther(this._scrollSpeed);
  2614 this._lineLayer=null;
  5162             break;
  2615 var D=("align" in this._params)?this._params.align:this._theme.ether.interval.marker[B.isHorizontal()?"hAlign":"vAlign"];
  5163         default:
  2616 var A=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
  5164             return true;
  2617 this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,D,A);
  5165         }
  2618 this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
  5166         this.closeBubble();
  2619 };
  5167 
  2620 Timeline.YearCountEtherPainter.prototype.setHighlight=function(A,B){this._highlight.position(A,B);
  5168         SimileAjax.DOM.cancelEvent(evt);
  2621 };
  5169         return false;
  2622 Timeline.YearCountEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
  5170     }
  2623 }this._markerLayer=this._band.createLayerDiv(100);
  5171     return true;
  2624 this._markerLayer.setAttribute("name","ether-markers");
  5172 };
  2625 this._markerLayer.style.display="none";
  5173 
  2626 if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
  5174 Timeline._Band.prototype._onKeyUp = function(keyboardInput, evt, target) {
  2627 }this._lineLayer=this._band.createLayerDiv(1);
  5175     if (!this._dragging) {
  2628 this._lineLayer.setAttribute("name","ether-lines");
  5176         this._scrollSpeed = this._originalScrollSpeed;
  2629 this._lineLayer.style.display="none";
  5177 
  2630 var B=new Date(this._startDate.getTime());
  5178         switch (evt.keyCode) {
  2631 var F=this._band.getMaxDate();
  5179         case 35: // end
  2632 var E=this._band.getMinDate().getUTCFullYear()-this._startDate.getUTCFullYear();
  5180             this.setCenterVisibleDate(this._eventSource.getLatestDate());
  2633 B.setUTCFullYear(this._band.getMinDate().getUTCFullYear()-E%this._multiple);
  5181             break;
  2634 var C=this;
  5182         case 36: // home
  2635 var A=function(G){for(var H=0;
  5183             this.setCenterVisibleDate(this._eventSource.getEarliestDate());
  2636 H<C._multiple;
  5184             break;
  2637 H++){SimileAjax.DateTime.incrementByInterval(G,SimileAjax.DateTime.YEAR);
  5185         case 33: // page up
  2638 }};
  5186             this._autoScroll(this._timeline.getPixelLength());
  2639 var D={labelInterval:function(G,I){var H=G.getUTCFullYear()-C._startDate.getUTCFullYear();
  5187             break;
  2640 return{text:H,emphasized:H==0};
  5188         case 34: // page down
  2641 }};
  5189             this._autoScroll(-this._timeline.getPixelLength());
  2642 while(B.getTime()<F.getTime()){this._intervalMarkerLayout.createIntervalMarker(B,D,SimileAjax.DateTime.YEAR,this._markerLayer,this._lineLayer);
  5190             break;
  2643 A(B);
  5191         default:
  2644 }this._markerLayer.style.display="block";
  5192             return true;
  2645 this._lineLayer.style.display="block";
  5193         }
  2646 };
  5194 
  2647 Timeline.YearCountEtherPainter.prototype.softPaint=function(){};
  5195         this.closeBubble();
  2648 Timeline.QuarterlyEtherPainter=function(A){this._params=A;
  5196 
  2649 this._theme=A.theme;
  5197         SimileAjax.DOM.cancelEvent(evt);
  2650 this._startDate=SimileAjax.DateTime.parseGregorianDateTime(A.startDate);
  5198         return false;
  2651 };
  5199     }
  2652 Timeline.QuarterlyEtherPainter.prototype.initialize=function(C,B){this._band=C;
  5200     return true;
  2653 this._timeline=B;
  5201 };
  2654 this._backgroundLayer=C.createLayerDiv(0);
  5202 
  2655 this._backgroundLayer.setAttribute("name","ether-background");
  5203 Timeline._Band.prototype._autoScroll = function(distance, f) {
  2656 this._backgroundLayer.className="timeline-ether-bg";
  5204     var b = this;
  2657 this._markerLayer=null;
  5205     var a = SimileAjax.Graphics.createAnimation(
  2658 this._lineLayer=null;
  5206         function(abs, diff) {
  2659 var D=("align" in this._params)?this._params.align:this._theme.ether.interval.marker[B.isHorizontal()?"hAlign":"vAlign"];
  5207             b._moveEther(diff);
  2660 var A=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
  5208         },
  2661 this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,D,A);
  5209         0,
  2662 this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
  5210         distance,
  2663 };
  5211         1000,
  2664 Timeline.QuarterlyEtherPainter.prototype.setHighlight=function(A,B){this._highlight.position(A,B);
  5212         f
  2665 };
  5213     );
  2666 Timeline.QuarterlyEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
  5214     a.run();
  2667 }this._markerLayer=this._band.createLayerDiv(100);
  5215 };
  2668 this._markerLayer.setAttribute("name","ether-markers");
  5216 
  2669 this._markerLayer.style.display="none";
  5217 Timeline._Band.prototype._moveEther = function(shift, orthogonalShift) {
  2670 if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
  5218     if (orthogonalShift === undefined) {
  2671 }this._lineLayer=this._band.createLayerDiv(1);
  5219         orthogonalShift = 0;
  2672 this._lineLayer.setAttribute("name","ether-lines");
  5220     }
  2673 this._lineLayer.style.display="none";
  5221 
  2674 var B=new Date(0);
  5222     this.closeBubble();
  2675 var E=this._band.getMaxDate();
  5223 
  2676 B.setUTCFullYear(Math.max(this._startDate.getUTCFullYear(),this._band.getMinDate().getUTCFullYear()));
  5224     // A positive shift means back in time
  2677 B.setUTCMonth(this._startDate.getUTCMonth());
  5225     // Check that we're not moving beyond Timeline's limits
  2678 var C=this;
  5226     if (!this._timeline.shiftOK(this._index, shift)) {
  2679 var A=function(F){F.setUTCMonth(F.getUTCMonth()+3);
  5227         return; // early return
  2680 };
  5228     }
  2681 var D={labelInterval:function(F,H){var G=(4+(F.getUTCMonth()-C._startDate.getUTCMonth())/3)%4;
  5229 
  2682 if(G!=0){return{text:"Q"+(G+1),emphasized:false};
  5230     this._viewOffset += shift;
  2683 }else{return{text:"Y"+(F.getUTCFullYear()-C._startDate.getUTCFullYear()+1),emphasized:true};
  5231     this._viewOrthogonalOffset = Math.min(0, this._viewOrthogonalOffset + orthogonalShift);
  2684 }}};
  5232 
  2685 while(B.getTime()<E.getTime()){this._intervalMarkerLayout.createIntervalMarker(B,D,SimileAjax.DateTime.YEAR,this._markerLayer,this._lineLayer);
  5233     this._ether.shiftPixels(-shift);
  2686 A(B);
  5234     if (this._timeline.isHorizontal()) {
  2687 }this._markerLayer.style.display="block";
  5235         this._div.style.left = this._viewOffset + "px";
  2688 this._lineLayer.style.display="block";
  5236     } else {
  2689 };
  5237         this._div.style.top = this._viewOffset + "px";
  2690 Timeline.QuarterlyEtherPainter.prototype.softPaint=function(){};
  5238     }
  2691 Timeline.EtherIntervalMarkerLayout=function(M,L,C,E,H){var A=M.isHorizontal();
  5239 
  2692 if(A){if(E=="Top"){this.positionDiv=function(O,N){O.style.left=N+"px";
  5240     if (this._viewOffset > -this._viewLength * 0.5 ||
  2693 O.style.top="0px";
  5241         this._viewOffset < -this._viewLength * (Timeline._Band.SCROLL_MULTIPLES - 1.5)) {
  2694 };
  5242 
  2695 }else{this.positionDiv=function(O,N){O.style.left=N+"px";
  5243         this._recenterDiv();
  2696 O.style.bottom="0px";
  5244     } else {
  2697 };
  5245         this.softLayout();
  2698 }}else{if(E=="Left"){this.positionDiv=function(O,N){O.style.top=N+"px";
  5246     }
  2699 O.style.left="0px";
  5247 
  2700 };
  5248     this._onChanging();
  2701 }else{this.positionDiv=function(O,N){O.style.top=N+"px";
  5249 }
  2702 O.style.right="0px";
  5250 
  2703 };
  5251 Timeline._Band.prototype._onChanging = function() {
  2704 }}var D=C.ether.interval.marker;
  5252     this._changing = true;
  2705 var I=C.ether.interval.line;
  5253 
  2706 var B=C.ether.interval.weekend;
  5254     this._fireOnScroll();
  2707 var K=(A?"h":"v")+E;
  5255     this._setSyncWithBandDate();
  2708 var G=D[K+"Styler"];
  5256 
  2709 var J=D[K+"EmphasizedStyler"];
  5257     this._changing = false;
  2710 var F=SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.DAY];
  5258 };
  2711 this.createIntervalMarker=function(T,a,b,c,Q){var U=Math.round(L.dateToPixelOffset(T));
  5259 
  2712 if(H&&b!=SimileAjax.DateTime.WEEK){var V=M.getDocument().createElement("div");
  5260 Timeline._Band.prototype.busy = function() {
  2713 V.className="timeline-ether-lines";
  5261     // Is this band busy changing other bands?
  2714 if(I.opacity<100){SimileAjax.Graphics.setOpacity(V,I.opacity);
  5262     return(this._changing);
  2715 }if(A){V.style.left=U+"px";
  5263 };
  2716 }else{V.style.top=U+"px";
  5264 
  2717 }Q.appendChild(V);
  5265 Timeline._Band.prototype._fireOnScroll = function() {
  2718 }if(b==SimileAjax.DateTime.WEEK){var N=C.firstDayOfWeek;
  5266     for (var i = 0; i < this._onScrollListeners.length; i++) {
  2719 var W=new Date(T.getTime()+(6-N-7)*F);
  5267         this._onScrollListeners[i](this);
  2720 var Z=new Date(W.getTime()+2*F);
  5268     }
  2721 var X=Math.round(L.dateToPixelOffset(W));
  5269 };
  2722 var S=Math.round(L.dateToPixelOffset(Z));
  5270 
  2723 var R=Math.max(1,S-X);
  5271 Timeline._Band.prototype._setSyncWithBandDate = function() {
  2724 var P=M.getDocument().createElement("div");
  5272     if (this._syncWithBand) {
  2725 P.className="timeline-ether-weekends";
  5273         var centerDate = this._ether.pixelOffsetToDate(this.getViewLength() / 2);
  2726 if(B.opacity<100){SimileAjax.Graphics.setOpacity(P,B.opacity);
  5274         this._syncWithBand.setCenterVisibleDate(centerDate);
  2727 }if(A){P.style.left=X+"px";
  5275     }
  2728 P.style.width=R+"px";
  5276 };
  2729 }else{P.style.top=X+"px";
  5277 
  2730 P.style.height=R+"px";
  5278 Timeline._Band.prototype._onHighlightBandScroll = function() {
  2731 }Q.appendChild(P);
  5279     if (this._syncWithBand) {
  2732 }var Y=a.labelInterval(T,b);
  5280         var centerDate = this._syncWithBand.getCenterVisibleDate();
  2733 var O=M.getDocument().createElement("div");
  5281         var centerPixelOffset = this._ether.dateToPixelOffset(centerDate);
  2734 O.innerHTML=Y.text;
  5282 
  2735 O.className="timeline-date-label";
  5283         this._moveEther(Math.round(this._viewLength / 2 - centerPixelOffset));
  2736 if(Y.emphasized){O.className+=" timeline-date-label-em";
  5284 
  2737 }this.positionDiv(O,U);
  5285         if (this._highlight) {
  2738 c.appendChild(O);
  5286             this._etherPainter.setHighlight(
  2739 return O;
  5287                 this._syncWithBand.getMinVisibleDate(),
  2740 };
  5288                 this._syncWithBand.getMaxVisibleDate());
  2741 };
  5289         }
  2742 Timeline.EtherHighlight=function(C,E,D,B){var A=C.isHorizontal();
  5290     }
  2743 this._highlightDiv=null;
  5291 };
  2744 this._createHighlightDiv=function(){if(this._highlightDiv==null){this._highlightDiv=C.getDocument().createElement("div");
  5292 
  2745 this._highlightDiv.setAttribute("name","ether-highlight");
  5293 Timeline._Band.prototype._onAddMany = function() {
  2746 this._highlightDiv.className="timeline-ether-highlight";
  5294     this._paintEvents();
  2747 var F=D.ether.highlightOpacity;
  5295 };
  2748 if(F<100){SimileAjax.Graphics.setOpacity(this._highlightDiv,F);
  5296 
  2749 }B.appendChild(this._highlightDiv);
  5297 Timeline._Band.prototype._onClear = function() {
  2750 }};
  5298     this._paintEvents();
  2751 this.position=function(F,I){this._createHighlightDiv();
  5299 };
  2752 var J=Math.round(E.dateToPixelOffset(F));
  5300 
  2753 var H=Math.round(E.dateToPixelOffset(I));
  5301 Timeline._Band.prototype._positionHighlight = function() {
  2754 var G=Math.max(H-J,3);
  5302     if (this._syncWithBand) {
  2755 if(A){this._highlightDiv.style.left=J+"px";
  5303         var startDate = this._syncWithBand.getMinVisibleDate();
  2756 this._highlightDiv.style.width=G+"px";
  5304         var endDate = this._syncWithBand.getMaxVisibleDate();
  2757 this._highlightDiv.style.height=(E.getViewWidth()-4)+"px";
  5305 
  2758 }else{this._highlightDiv.style.top=J+"px";
  5306         if (this._highlight) {
  2759 this._highlightDiv.style.height=G+"px";
  5307             this._etherPainter.setHighlight(startDate, endDate);
  2760 this._highlightDiv.style.width=(E.getViewWidth()-4)+"px";
  5308         }
  2761 }};
  5309     }
  2762 };
  5310 };
  2763 
  5311 
  2764 
  5312 Timeline._Band.prototype._recenterDiv = function() {
  2765 /* ethers.js */
  5313     this._viewOffset = -this._viewLength * (Timeline._Band.SCROLL_MULTIPLES - 1) / 2;
  2766 Timeline.LinearEther=function(A){this._params=A;
  5314     if (this._timeline.isHorizontal()) {
  2767 this._interval=A.interval;
  5315         this._div.style.left = this._viewOffset + "px";
  2768 this._pixelsPerInterval=A.pixelsPerInterval;
  5316         this._div.style.width = (Timeline._Band.SCROLL_MULTIPLES * this._viewLength) + "px";
  2769 };
  5317     } else {
  2770 Timeline.LinearEther.prototype.initialize=function(B,A){this._band=B;
  5318         this._div.style.top = this._viewOffset + "px";
  2771 this._timeline=A;
  5319         this._div.style.height = (Timeline._Band.SCROLL_MULTIPLES * this._viewLength) + "px";
  2772 this._unit=A.getUnit();
  5320     }
  2773 if("startsOn" in this._params){this._start=this._unit.parseFromObject(this._params.startsOn);
  5321     this.layout();
  2774 }else{if("endsOn" in this._params){this._start=this._unit.parseFromObject(this._params.endsOn);
  5322 };
  2775 this.shiftPixels(-this._timeline.getPixelLength());
  5323 
  2776 }else{if("centersOn" in this._params){this._start=this._unit.parseFromObject(this._params.centersOn);
  5324 Timeline._Band.prototype._paintEvents = function() {
  2777 this.shiftPixels(-this._timeline.getPixelLength()/2);
  5325     this._eventPainter.paint();
  2778 }else{this._start=this._unit.makeDefaultValue();
  5326 };
  2779 this.shiftPixels(-this._timeline.getPixelLength()/2);
  5327 
  2780 }}}};
  5328 Timeline._Band.prototype._softPaintEvents = function() {
  2781 Timeline.LinearEther.prototype.setDate=function(A){this._start=this._unit.cloneValue(A);
  5329     this._eventPainter.softPaint();
  2782 };
  5330 };
  2783 Timeline.LinearEther.prototype.shiftPixels=function(B){var A=this._interval*B/this._pixelsPerInterval;
  5331 
  2784 this._start=this._unit.change(this._start,A);
  5332 Timeline._Band.prototype._paintDecorators = function() {
  2785 };
  5333     for (var i = 0; i < this._decorators.length; i++) {
  2786 Timeline.LinearEther.prototype.dateToPixelOffset=function(A){var B=this._unit.compare(A,this._start);
  5334         this._decorators[i].paint();
  2787 return this._pixelsPerInterval*B/this._interval;
  5335     }
  2788 };
  5336 };
  2789 Timeline.LinearEther.prototype.pixelOffsetToDate=function(B){var A=B*this._interval/this._pixelsPerInterval;
  5337 
  2790 return this._unit.change(this._start,A);
  5338 Timeline._Band.prototype._softPaintDecorators = function() {
  2791 };
  5339     for (var i = 0; i < this._decorators.length; i++) {
  2792 Timeline.LinearEther.prototype.zoom=function(D){var B=0;
  5340         this._decorators[i].softPaint();
  2793 var A=this._band._zoomIndex;
  5341     }
  2794 var C=A;
  5342 };
  2795 if(D&&(A>0)){C=A-1;
  5343 
  2796 }if(!D&&(A<(this._band._zoomSteps.length-1))){C=A+1;
  5344 Timeline._Band.prototype.closeBubble = function() {
  2797 }this._band._zoomIndex=C;
  5345     SimileAjax.WindowManager.cancelPopups();
  2798 this._interval=SimileAjax.DateTime.gregorianUnitLengths[this._band._zoomSteps[C].unit];
  5346 };
  2799 this._pixelsPerInterval=this._band._zoomSteps[C].pixelsPerInterval;
  5347 /*==================================================
  2800 B=this._band._zoomSteps[C].unit-this._band._zoomSteps[A].unit;
  5348  *  Classic Theme
  2801 return B;
  5349  *==================================================
  2802 };
  5350  */
  2803 Timeline.HotZoneEther=function(A){this._params=A;
  5351 
  2804 this._interval=A.interval;
  5352 
  2805 this._pixelsPerInterval=A.pixelsPerInterval;
  5353 
  2806 this._theme=A.theme;
  5354 Timeline.ClassicTheme = new Object();
  2807 };
  5355 
  2808 Timeline.HotZoneEther.prototype.initialize=function(H,I){this._band=H;
  5356 Timeline.ClassicTheme.implementations = [];
  2809 this._timeline=I;
  5357 
  2810 this._unit=I.getUnit();
  5358 Timeline.ClassicTheme.create = function(locale) {
  2811 this._zones=[{startTime:Number.NEGATIVE_INFINITY,endTime:Number.POSITIVE_INFINITY,magnify:1}];
  5359     if (locale == null) {
  2812 var B=this._params;
  5360         locale = Timeline.getDefaultLocale();
  2813 for(var D=0;
  5361     }
  2814 D<B.zones.length;
  5362 
  2815 D++){var G=B.zones[D];
  5363     var f = Timeline.ClassicTheme.implementations[locale];
  2816 var E=this._unit.parseFromObject(G.start);
  5364     if (f == null) {
  2817 var F=this._unit.parseFromObject(G.end);
  5365         f = Timeline.ClassicTheme._Impl;
  2818 for(var C=0;
  5366     }
  2819 C<this._zones.length&&this._unit.compare(F,E)>0;
  5367     return new f();
  2820 C++){var A=this._zones[C];
  5368 };
  2821 if(this._unit.compare(E,A.endTime)<0){if(this._unit.compare(E,A.startTime)>0){this._zones.splice(C,0,{startTime:A.startTime,endTime:E,magnify:A.magnify});
  5369 
  2822 C++;
  5370 Timeline.ClassicTheme._Impl = function() {
  2823 A.startTime=E;
  5371     this.firstDayOfWeek = 0; // Sunday
  2824 }if(this._unit.compare(F,A.endTime)<0){this._zones.splice(C,0,{startTime:E,endTime:F,magnify:G.magnify*A.magnify});
  5372 
  2825 C++;
  5373     // Note: Many styles previously set here are now set using CSS
  2826 A.startTime=F;
  5374     //       The comments indicate settings controlled by CSS, not
  2827 E=F;
  5375     //       lines to be un-commented.
  2828 }else{A.magnify*=G.magnify;
  5376     //
  2829 E=A.endTime;
  5377     //
  2830 }}}}if("startsOn" in this._params){this._start=this._unit.parseFromObject(this._params.startsOn);
  5378     // Attributes autoWidth, autoWidthAnimationTime, timeline_start
  2831 }else{if("endsOn" in this._params){this._start=this._unit.parseFromObject(this._params.endsOn);
  5379     // and timeline_stop must be set on the first band's theme.
  2832 this.shiftPixels(-this._timeline.getPixelLength());
  5380     // The other attributes can be set differently for each
  2833 }else{if("centersOn" in this._params){this._start=this._unit.parseFromObject(this._params.centersOn);
  5381     // band by using different themes for the bands.
  2834 this.shiftPixels(-this._timeline.getPixelLength()/2);
  5382     this.autoWidth = false; // Should the Timeline automatically grow itself, as
  2835 }else{this._start=this._unit.makeDefaultValue();
  5383                             // needed when too many events for the available width
  2836 this.shiftPixels(-this._timeline.getPixelLength()/2);
  5384                             // are painted on the visible part of the Timeline?
  2837 }}}};
  5385     this.autoWidthAnimationTime = 500; // mSec
  2838 Timeline.HotZoneEther.prototype.setDate=function(A){this._start=this._unit.cloneValue(A);
  5386     this.timeline_start = null; // Setting a date, eg new Date(Date.UTC(2008,0,17,20,00,00,0)) will prevent the
  2839 };
  5387                                 // Timeline from being moved to anytime before the date.
  2840 Timeline.HotZoneEther.prototype.shiftPixels=function(A){this._start=this.pixelOffsetToDate(A);
  5388     this.timeline_stop = null;  // Use for setting a maximum date. The Timeline will not be able
  2841 };
  5389                                 // to be moved to anytime after this date.
  2842 Timeline.HotZoneEther.prototype.dateToPixelOffset=function(A){return this._dateDiffToPixelOffset(this._start,A);
  5390     this.ether = {
  2843 };
  5391         backgroundColors: [
  2844 Timeline.HotZoneEther.prototype.pixelOffsetToDate=function(A){return this._pixelOffsetToDate(A,this._start);
  5392         //    "#EEE",
  2845 };
  5393         //    "#DDD",
  2846 Timeline.HotZoneEther.prototype.zoom=function(D){var B=0;
  5394         //    "#CCC",
  2847 var A=this._band._zoomIndex;
  5395         //    "#AAA"
  2848 var C=A;
  5396         ],
  2849 if(D&&(A>0)){C=A-1;
  5397      //   highlightColor:     "white",
  2850 }if(!D&&(A<(this._band._zoomSteps.length-1))){C=A+1;
  5398         highlightOpacity:   50,
  2851 }this._band._zoomIndex=C;
  5399         interval: {
  2852 this._interval=SimileAjax.DateTime.gregorianUnitLengths[this._band._zoomSteps[C].unit];
  5400             line: {
  2853 this._pixelsPerInterval=this._band._zoomSteps[C].pixelsPerInterval;
  5401                 show:       true,
  2854 B=this._band._zoomSteps[C].unit-this._band._zoomSteps[A].unit;
  5402                 opacity:    25
  2855 return B;
  5403                // color:      "#aaa",
  2856 };
  5404             },
  2857 Timeline.HotZoneEther.prototype._dateDiffToPixelOffset=function(I,D){var B=this._getScale();
  5405             weekend: {
  2858 var H=I;
  5406                 opacity:    30
  2859 var C=D;
  5407               //  color:      "#FFFFE0",
  2860 var A=0;
  5408             },
  2861 if(this._unit.compare(H,C)<0){var G=0;
  5409             marker: {
  2862 while(G<this._zones.length){if(this._unit.compare(H,this._zones[G].endTime)<0){break;
  5410                 hAlign:     "Bottom",
  2863 }G++;
  5411                 vAlign:     "Right"
  2864 }while(this._unit.compare(H,C)<0){var E=this._zones[G];
  5412                                         /*
  2865 var F=this._unit.earlier(C,E.endTime);
  5413                 hBottomStyler: function(elmt) {
  2866 A+=(this._unit.compare(F,H)/(B/E.magnify));
  5414                     elmt.className = "timeline-ether-marker-bottom";
  2867 H=F;
  5415                 },
  2868 G++;
  5416                 hBottomEmphasizedStyler: function(elmt) {
  2869 }}else{var G=this._zones.length-1;
  5417                     elmt.className = "timeline-ether-marker-bottom-emphasized";
  2870 while(G>=0){if(this._unit.compare(H,this._zones[G].startTime)>0){break;
  5418                 },
  2871 }G--;
  5419                 hTopStyler: function(elmt) {
  2872 }while(this._unit.compare(H,C)>0){var E=this._zones[G];
  5420                     elmt.className = "timeline-ether-marker-top";
  2873 var F=this._unit.later(C,E.startTime);
  5421                 },
  2874 A+=(this._unit.compare(F,H)/(B/E.magnify));
  5422                 hTopEmphasizedStyler: function(elmt) {
  2875 H=F;
  5423                     elmt.className = "timeline-ether-marker-top-emphasized";
  2876 G--;
  5424                 },
  2877 }}return A;
  5425                 */
  2878 };
  5426 
  2879 Timeline.HotZoneEther.prototype._pixelOffsetToDate=function(H,C){var G=this._getScale();
  5427 
  2880 var E=C;
  5428                /*
  2881 if(H>0){var F=0;
  5429                                   vRightStyler: function(elmt) {
  2882 while(F<this._zones.length){if(this._unit.compare(E,this._zones[F].endTime)<0){break;
  5430                     elmt.className = "timeline-ether-marker-right";
  2883 }F++;
  5431                 },
  2884 }while(H>0){var A=this._zones[F];
  5432                 vRightEmphasizedStyler: function(elmt) {
  2885 var D=G/A.magnify;
  5433                     elmt.className = "timeline-ether-marker-right-emphasized";
  2886 if(A.endTime==Number.POSITIVE_INFINITY){E=this._unit.change(E,H*D);
  5434                 },
  2887 H=0;
  5435                 vLeftStyler: function(elmt) {
  2888 }else{var B=this._unit.compare(A.endTime,E)/D;
  5436                     elmt.className = "timeline-ether-marker-left";
  2889 if(B>H){E=this._unit.change(E,H*D);
  5437                 },
  2890 H=0;
  5438                 vLeftEmphasizedStyler:function(elmt) {
  2891 }else{E=A.endTime;
  5439                     elmt.className = "timeline-ether-marker-left-emphasized";
  2892 H-=B;
  5440                 }
  2893 }}F++;
  5441                 */
  2894 }}else{var F=this._zones.length-1;
  5442             }
  2895 while(F>=0){if(this._unit.compare(E,this._zones[F].startTime)>0){break;
  5443         }
  2896 }F--;
  5444     };
  2897 }H=-H;
  5445 
  2898 while(H>0){var A=this._zones[F];
  5446     this.event = {
  2899 var D=G/A.magnify;
  5447         track: {
  2900 if(A.startTime==Number.NEGATIVE_INFINITY){E=this._unit.change(E,-H*D);
  5448                    height: 10, // px. You will need to change the track
  2901 H=0;
  5449                                //     height if you change the tape height.
  2902 }else{var B=this._unit.compare(E,A.startTime)/D;
  5450                       gap:  2, // px. Gap between tracks
  2903 if(B>H){E=this._unit.change(E,-H*D);
  5451                    offset:  2, // px. top margin above tapes
  2904 H=0;
  5452           autoWidthMargin:  1.5
  2905 }else{E=A.startTime;
  5453           /* autoWidthMargin is only used if autoWidth (see above) is true.
  2906 H-=B;
  5454              The autoWidthMargin setting is used to set how close the bottom of the
  2907 }}F--;
  5455              lowest track is to the edge of the band's div. The units are total track
  2908 }}return E;
  5456              width (tape + label + gap). A min of 0.5 is suggested. Use this setting to
  2909 };
  5457              move the bottom track's tapes above the axis markers, if needed for your
  2910 Timeline.HotZoneEther.prototype._getScale=function(){return this._interval/this._pixelsPerInterval;
  5458              Timeline.
  2911 };
  5459           */
  2912 
  5460         },
  2913 
  5461         overviewTrack: {
  2914 /* event-utils.js */
  5462                   offset: 20, // px -- top margin above tapes
  2915 Timeline.EventUtils={};
  5463               tickHeight:  6, // px
  2916 Timeline.EventUtils.getNewEventID=function(){if(this._lastEventID==null){this._lastEventID=0;
  5464                   height:  2, // px
  2917 }this._lastEventID+=1;
  5465                      gap:  1, // px
  2918 return"e"+this._lastEventID;
  5466          autoWidthMargin:  5 // This attribute is only used if autoWidth (see above) is true.
  2919 };
  5467         },
  2920 Timeline.EventUtils.decodeEventElID=function(B){var D=B.split("-");
  5468         tape: {
  2921 if(D[1]!="tl"){alert("Internal Timeline problem 101, please consult support");
  5469             height:         4 // px. For thicker tapes, remember to change track height too.
  2922 return{band:null,evt:null};
  5470         },
  2923 }var C=Timeline.getTimelineFromID(D[2]);
  5471         instant: {
  2924 var E=C.getBand(D[3]);
  5472                            icon: Timeline.urlPrefix + "images/dull-blue-circle.png",
  2925 var A=E.getEventSource.getEvent(D[4]);
  5473                                  // default icon. Icon can also be specified per event
  2926 return{band:E,evt:A};
  5474                       iconWidth: 10,
  2927 };
  5475                      iconHeight: 10,
  2928 Timeline.EventUtils.encodeEventElID=function(C,D,B,A){return B+"-tl-"+C.timelineID+"-"+D.getIndex()+"-"+A.getID();
  5476                impreciseOpacity: 20, // opacity of the tape when durationEvent is false
  2929 };
  5477             impreciseIconMargin: 3   // A tape and an icon are painted for imprecise instant
  2930 
  5478                                      // events. This attribute is the margin between the
  2931 
  5479                                      // bottom of the tape and the top of the icon in that
  2932 /* labellers.js */
  5480                                      // case.
  2933 Timeline.GregorianDateLabeller=function(A,B){this._locale=A;
  5481     //        color:             "#58A0DC",
  2934 this._timeZone=B;
  5482     //        impreciseColor:    "#58A0DC",
  2935 };
  5483         },
  2936 Timeline.GregorianDateLabeller.monthNames=[];
  5484         duration: {
  2937 Timeline.GregorianDateLabeller.dayNames=[];
  5485             impreciseOpacity: 20 // tape opacity for imprecise part of duration events
  2938 Timeline.GregorianDateLabeller.labelIntervalFunctions=[];
  5486       //      color:            "#58A0DC",
  2939 Timeline.GregorianDateLabeller.getMonthName=function(B,A){return Timeline.GregorianDateLabeller.monthNames[A][B];
  5487       //      impreciseColor:   "#58A0DC",
  2940 };
  5488         },
  2941 Timeline.GregorianDateLabeller.prototype.labelInterval=function(A,C){var B=Timeline.GregorianDateLabeller.labelIntervalFunctions[this._locale];
  5489         label: {
  2942 if(B==null){B=Timeline.GregorianDateLabeller.prototype.defaultLabelInterval;
  5490             backgroundOpacity: 50,// only used in detailed painter
  2943 }return B.call(this,A,C);
  5491                offsetFromLine:  3 // px left margin amount from icon's right edge
  2944 };
  5492       //      backgroundColor:   "white",
  2945 Timeline.GregorianDateLabeller.prototype.labelPrecise=function(A){return SimileAjax.DateTime.removeTimeZoneOffset(A,this._timeZone).toUTCString();
  5493       //      lineColor:         "#58A0DC",
  2946 };
  5494         },
  2947 Timeline.GregorianDateLabeller.prototype.defaultLabelInterval=function(B,F){var C;
  5495         highlightColors: [  // Use with getEventPainter().setHighlightMatcher
  2948 var E=false;
  5496                             // See webapp/examples/examples.js
  2949 B=SimileAjax.DateTime.removeTimeZoneOffset(B,this._timeZone);
  5497             "#FFFF00",
  2950 switch(F){case SimileAjax.DateTime.MILLISECOND:C=B.getUTCMilliseconds();
  5498             "#FFC000",
  2951 break;
  5499             "#FF0000",
  2952 case SimileAjax.DateTime.SECOND:C=B.getUTCSeconds();
  5500             "#0000FF"
  2953 break;
  5501         ],
  2954 case SimileAjax.DateTime.MINUTE:var A=B.getUTCMinutes();
  5502         highlightLabelBackground: false, // When highlighting an event, also change the event's label background?
  2955 if(A==0){C=B.getUTCHours()+":00";
  5503         bubble: {
  2956 E=true;
  5504             width:          250, // px
  2957 }else{C=A;
  5505             maxHeight:        0, // px Maximum height of bubbles. 0 means no max height.
  2958 }break;
  5506                                  // scrollbar will be added for taller bubbles
  2959 case SimileAjax.DateTime.HOUR:C=B.getUTCHours()+"hr";
  5507             titleStyler: function(elmt) {
  2960 break;
  5508                 elmt.className = "timeline-event-bubble-title";
  2961 case SimileAjax.DateTime.DAY:C=Timeline.GregorianDateLabeller.getMonthName(B.getUTCMonth(),this._locale)+" "+B.getUTCDate();
  5509             },
  2962 break;
  5510             bodyStyler: function(elmt) {
  2963 case SimileAjax.DateTime.WEEK:C=Timeline.GregorianDateLabeller.getMonthName(B.getUTCMonth(),this._locale)+" "+B.getUTCDate();
  5511                 elmt.className = "timeline-event-bubble-body";
  2964 break;
  5512             },
  2965 case SimileAjax.DateTime.MONTH:var A=B.getUTCMonth();
  5513             imageStyler: function(elmt) {
  2966 if(A!=0){C=Timeline.GregorianDateLabeller.getMonthName(A,this._locale);
  5514                 elmt.className = "timeline-event-bubble-image";
  2967 break;
  5515             },
  2968 }case SimileAjax.DateTime.YEAR:case SimileAjax.DateTime.DECADE:case SimileAjax.DateTime.CENTURY:case SimileAjax.DateTime.MILLENNIUM:var D=B.getUTCFullYear();
  5516             wikiStyler: function(elmt) {
  2969 if(D>0){C=B.getUTCFullYear();
  5517                 elmt.className = "timeline-event-bubble-wiki";
  2970 }else{C=(1-D)+"BC";
  5518             },
  2971 }E=(F==SimileAjax.DateTime.MONTH)||(F==SimileAjax.DateTime.DECADE&&D%100==0)||(F==SimileAjax.DateTime.CENTURY&&D%1000==0);
  5519             timeStyler: function(elmt) {
  2972 break;
  5520                 elmt.className = "timeline-event-bubble-time";
  2973 default:C=B.toUTCString();
  5521             }
  2974 }return{text:C,emphasized:E};
  5522         }
  2975 };
  5523     };
  2976 
  5524 
  2977 
  5525     this.mouseWheel = 'scroll'; // 'default', 'zoom', 'scroll'
  2978 /* original-painter.js */
  5526 };/*==================================================
  2979 Timeline.OriginalEventPainter=function(A){this._params=A;
  5527  *  An "ether" is a object that maps date/time to pixel coordinates.
  2980 this._onSelectListeners=[];
  5528  *==================================================
  2981 this._eventPaintListeners=[];
  5529  */
  2982 this._filterMatcher=null;
  5530 
  2983 this._highlightMatcher=null;
  5531 /*==================================================
  2984 this._frc=null;
  5532  *  Linear Ether
  2985 this._eventIdToElmt={};
  5533  *==================================================
  2986 };
  5534  */
  2987 Timeline.OriginalEventPainter.prototype.initialize=function(B,A){this._band=B;
  5535 
  2988 this._timeline=A;
  5536 Timeline.LinearEther = function(params) {
  2989 this._backLayer=null;
  5537     this._params = params;
  2990 this._eventLayer=null;
  5538     this._interval = params.interval;
  2991 this._lineLayer=null;
  5539     this._pixelsPerInterval = params.pixelsPerInterval;
  2992 this._highlightLayer=null;
  5540 };
  2993 this._eventIdToElmt=null;
  5541 
  2994 };
  5542 Timeline.LinearEther.prototype.initialize = function(band, timeline) {
  2995 Timeline.OriginalEventPainter.prototype.getType=function(){return"original";
  5543     this._band = band;
  2996 };
  5544     this._timeline = timeline;
  2997 Timeline.OriginalEventPainter.prototype.addOnSelectListener=function(A){this._onSelectListeners.push(A);
  5545     this._unit = timeline.getUnit();
  2998 };
  5546 
  2999 Timeline.OriginalEventPainter.prototype.removeOnSelectListener=function(B){for(var A=0;
  5547     if ("startsOn" in this._params) {
  3000 A<this._onSelectListeners.length;
  5548         this._start = this._unit.parseFromObject(this._params.startsOn);
  3001 A++){if(this._onSelectListeners[A]==B){this._onSelectListeners.splice(A,1);
  5549     } else if ("endsOn" in this._params) {
  3002 break;
  5550         this._start = this._unit.parseFromObject(this._params.endsOn);
  3003 }}};
  5551         this.shiftPixels(-this._timeline.getPixelLength());
  3004 Timeline.OriginalEventPainter.prototype.addEventPaintListener=function(A){this._eventPaintListeners.push(A);
  5552     } else if ("centersOn" in this._params) {
  3005 };
  5553         this._start = this._unit.parseFromObject(this._params.centersOn);
  3006 Timeline.OriginalEventPainter.prototype.removeEventPaintListener=function(B){for(var A=0;
  5554         this.shiftPixels(-this._timeline.getPixelLength() / 2);
  3007 A<this._eventPaintListeners.length;
  5555     } else {
  3008 A++){if(this._eventPaintListeners[A]==B){this._eventPaintListeners.splice(A,1);
  5556         this._start = this._unit.makeDefaultValue();
  3009 break;
  5557         this.shiftPixels(-this._timeline.getPixelLength() / 2);
  3010 }}};
  5558     }
  3011 Timeline.OriginalEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
  5559 };
  3012 };
  5560 
  3013 Timeline.OriginalEventPainter.prototype.setFilterMatcher=function(A){this._filterMatcher=A;
  5561 Timeline.LinearEther.prototype.setDate = function(date) {
  3014 };
  5562     this._start = this._unit.cloneValue(date);
  3015 Timeline.OriginalEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
  5563 };
  3016 };
  5564 
  3017 Timeline.OriginalEventPainter.prototype.setHighlightMatcher=function(A){this._highlightMatcher=A;
  5565 Timeline.LinearEther.prototype.shiftPixels = function(pixels) {
  3018 };
  5566     var numeric = this._interval * pixels / this._pixelsPerInterval;
  3019 Timeline.OriginalEventPainter.prototype.paint=function(){var B=this._band.getEventSource();
  5567     this._start = this._unit.change(this._start, numeric);
  3020 if(B==null){return ;
  5568 };
  3021 }this._eventIdToElmt={};
  5569 
  3022 this._fireEventPaintListeners("paintStarting",null,null);
  5570 Timeline.LinearEther.prototype.dateToPixelOffset = function(date) {
  3023 this._prepareForPainting();
  5571     var numeric = this._unit.compare(date, this._start);
  3024 var I=this._params.theme.event;
  5572     return this._pixelsPerInterval * numeric / this._interval;
  3025 var G=Math.max(I.track.height,I.tape.height+this._frc.getLineHeight());
  5573 };
  3026 var F={trackOffset:I.track.offset,trackHeight:G,trackGap:I.track.gap,trackIncrement:G+I.track.gap,icon:I.instant.icon,iconWidth:I.instant.iconWidth,iconHeight:I.instant.iconHeight,labelWidth:I.label.width,maxLabelChar:I.label.maxLabelChar,impreciseIconMargin:I.instant.impreciseIconMargin};
  5574 
  3027 var C=this._band.getMinDate();
  5575 Timeline.LinearEther.prototype.pixelOffsetToDate = function(pixels) {
  3028 var A=this._band.getMaxDate();
  5576     var numeric = pixels * this._interval / this._pixelsPerInterval;
  3029 var J=(this._filterMatcher!=null)?this._filterMatcher:function(K){return true;
  5577     return this._unit.change(this._start, numeric);
  3030 };
  5578 };
  3031 var E=(this._highlightMatcher!=null)?this._highlightMatcher:function(K){return -1;
  5579 
  3032 };
  5580 Timeline.LinearEther.prototype.zoom = function(zoomIn) {
  3033 var D=B.getEventReverseIterator(C,A);
  5581   var netIntervalChange = 0;
  3034 while(D.hasNext()){var H=D.next();
  5582   var currentZoomIndex = this._band._zoomIndex;
  3035 if(J(H)){this.paintEvent(H,F,this._params.theme,E(H));
  5583   var newZoomIndex = currentZoomIndex;
  3036 }}this._highlightLayer.style.display="block";
  5584 
  3037 this._lineLayer.style.display="block";
  5585   if (zoomIn && (currentZoomIndex > 0)) {
  3038 this._eventLayer.style.display="block";
  5586     newZoomIndex = currentZoomIndex - 1;
  3039 this._band.updateEventTrackInfo(this._tracks.length,F.trackIncrement);
  5587   }
  3040 this._fireEventPaintListeners("paintEnded",null,null);
  5588 
  3041 };
  5589   if (!zoomIn && (currentZoomIndex < (this._band._zoomSteps.length - 1))) {
  3042 Timeline.OriginalEventPainter.prototype.softPaint=function(){};
  5590     newZoomIndex = currentZoomIndex + 1;
  3043 Timeline.OriginalEventPainter.prototype._prepareForPainting=function(){var B=this._band;
  5591   }
  3044 if(this._backLayer==null){this._backLayer=this._band.createLayerDiv(0,"timeline-band-events");
  5592 
  3045 this._backLayer.style.visibility="hidden";
  5593   this._band._zoomIndex = newZoomIndex;
  3046 var A=document.createElement("span");
  5594   this._interval =
  3047 A.className="timeline-event-label";
  5595     SimileAjax.DateTime.gregorianUnitLengths[this._band._zoomSteps[newZoomIndex].unit];
  3048 this._backLayer.appendChild(A);
  5596   this._pixelsPerInterval = this._band._zoomSteps[newZoomIndex].pixelsPerInterval;
  3049 this._frc=SimileAjax.Graphics.getFontRenderingContext(A);
  5597   netIntervalChange = this._band._zoomSteps[newZoomIndex].unit -
  3050 }this._frc.update();
  5598     this._band._zoomSteps[currentZoomIndex].unit;
  3051 this._tracks=[];
  5599 
  3052 if(this._highlightLayer!=null){B.removeLayerDiv(this._highlightLayer);
  5600   return netIntervalChange;
  3053 }this._highlightLayer=B.createLayerDiv(105,"timeline-band-highlights");
  5601 };
  3054 this._highlightLayer.style.display="none";
  5602 
  3055 if(this._lineLayer!=null){B.removeLayerDiv(this._lineLayer);
  5603 
  3056 }this._lineLayer=B.createLayerDiv(110,"timeline-band-lines");
  5604 /*==================================================
  3057 this._lineLayer.style.display="none";
  5605  *  Hot Zone Ether
  3058 if(this._eventLayer!=null){B.removeLayerDiv(this._eventLayer);
  5606  *==================================================
  3059 }this._eventLayer=B.createLayerDiv(115,"timeline-band-events");
  5607  */
  3060 this._eventLayer.style.display="none";
  5608 
  3061 };
  5609 Timeline.HotZoneEther = function(params) {
  3062 Timeline.OriginalEventPainter.prototype.paintEvent=function(B,C,D,A){if(B.isInstant()){this.paintInstantEvent(B,C,D,A);
  5610     this._params = params;
  3063 }else{this.paintDurationEvent(B,C,D,A);
  5611     this._interval = params.interval;
  3064 }};
  5612     this._pixelsPerInterval = params.pixelsPerInterval;
  3065 Timeline.OriginalEventPainter.prototype.paintInstantEvent=function(B,C,D,A){if(B.isImprecise()){this.paintImpreciseInstantEvent(B,C,D,A);
  5613     this._theme = params.theme;
  3066 }else{this.paintPreciseInstantEvent(B,C,D,A);
  5614 };
  3067 }};
  5615 
  3068 Timeline.OriginalEventPainter.prototype.paintDurationEvent=function(B,C,D,A){if(B.isImprecise()){this.paintImpreciseDurationEvent(B,C,D,A);
  5616 Timeline.HotZoneEther.prototype.initialize = function(band, timeline) {
  3069 }else{this.paintPreciseDurationEvent(B,C,D,A);
  5617     this._band = band;
  3070 }};
  5618     this._timeline = timeline;
  3071 Timeline.OriginalEventPainter.prototype.paintPreciseInstantEvent=function(M,Q,S,R){var V=this._timeline.getDocument();
  5619     this._unit = timeline.getUnit();
  3072 var L=M.getText();
  5620 
  3073 var E=M.getStart();
  5621     this._zones = [{
  3074 var C=Math.round(this._band.dateToPixelOffset(E));
  5622         startTime:  Number.NEGATIVE_INFINITY,
  3075 var A=Math.round(C+Q.iconWidth/2);
  5623         endTime:    Number.POSITIVE_INFINITY,
  3076 var K=Math.round(C-Q.iconWidth/2);
  5624         magnify:    1
  3077 var H=this._getLabelDivClassName(M);
  5625     }];
  3078 var I=this._frc.computeSize(L,H);
  5626     var params = this._params;
  3079 var W=A+S.event.label.offsetFromLine;
  5627     for (var i = 0; i < params.zones.length; i++) {
  3080 var D=W+I.width;
  5628         var zone = params.zones[i];
  3081 var U=D;
  5629         var zoneStart = this._unit.parseFromObject(zone.start);
  3082 var O=this._findFreeTrack(M,U);
  5630         var zoneEnd =   this._unit.parseFromObject(zone.end);
  3083 var T=Math.round(Q.trackOffset+O*Q.trackIncrement+Q.trackHeight/2-I.height/2);
  5631 
  3084 var B=this._paintEventIcon(M,O,K,Q,S,0);
  5632         for (var j = 0; j < this._zones.length && this._unit.compare(zoneEnd, zoneStart) > 0; j++) {
  3085 var P=this._paintEventLabel(M,L,W,T,I.width,I.height,S,H,R);
  5633             var zone2 = this._zones[j];
  3086 var F=[B.elmt,P.elmt];
  5634 
  3087 var N=this;
  5635             if (this._unit.compare(zoneStart, zone2.endTime) < 0) {
  3088 var J=function(X,Y,Z){return N._onClickInstantEvent(B.elmt,Y,M);
  5636                 if (this._unit.compare(zoneStart, zone2.startTime) > 0) {
  3089 };
  5637                     this._zones.splice(j, 0, {
  3090 SimileAjax.DOM.registerEvent(B.elmt,"mousedown",J);
  5638                         startTime:   zone2.startTime,
  3091 SimileAjax.DOM.registerEvent(P.elmt,"mousedown",J);
  5639                         endTime:     zoneStart,
  3092 var G=this._createHighlightDiv(R,B,S,M);
  5640                         magnify:     zone2.magnify
  3093 if(G!=null){F.push(G);
  5641                     });
  3094 }this._fireEventPaintListeners("paintedEvent",M,F);
  5642                     j++;
  3095 this._eventIdToElmt[M.getID()]=B.elmt;
  5643 
  3096 this._tracks[O]=K;
  5644                     zone2.startTime = zoneStart;
  3097 };
  5645                 }
  3098 Timeline.OriginalEventPainter.prototype.paintImpreciseInstantEvent=function(P,T,Y,V){var a=this._timeline.getDocument();
  5646 
  3099 var N=P.getText();
  5647                 if (this._unit.compare(zoneEnd, zone2.endTime) < 0) {
  3100 var G=P.getStart();
  5648                     this._zones.splice(j, 0, {
  3101 var W=P.getEnd();
  5649                         startTime:  zoneStart,
  3102 var D=Math.round(this._band.dateToPixelOffset(G));
  5650                         endTime:    zoneEnd,
  3103 var B=Math.round(this._band.dateToPixelOffset(W));
  5651                         magnify:    zone.magnify * zone2.magnify
  3104 var A=Math.round(D+T.iconWidth/2);
  5652                     });
  3105 var M=Math.round(D-T.iconWidth/2);
  5653                     j++;
  3106 var J=this._getLabelDivClassName(P);
  5654 
  3107 var K=this._frc.computeSize(N,J);
  5655                     zone2.startTime = zoneEnd;
  3108 var b=A+Y.event.label.offsetFromLine;
  5656                     zoneStart = zoneEnd;
  3109 var E=b+K.width;
  5657                 } else {
  3110 var Z=Math.max(E,B);
  5658                     zone2.magnify *= zone.magnify;
  3111 var R=this._findFreeTrack(P,Z);
  5659                     zoneStart = zone2.endTime;
  3112 var O=Y.event.tape.height;
  5660                 }
  3113 var X=Math.round(T.trackOffset+R*T.trackIncrement+O);
  5661             } // else, try the next existing zone
  3114 var C=this._paintEventIcon(P,R,M,T,Y,O);
  5662         }
  3115 var S=this._paintEventLabel(P,N,b,X,K.width,K.height,Y,J,V);
  5663     }
  3116 var U=P.getColor();
  5664 
  3117 U=U!=null?U:Y.event.instant.impreciseColor;
  5665     if ("startsOn" in this._params) {
  3118 var F=this._paintEventTape(P,R,D,B,U,Y.event.instant.impreciseOpacity,T,Y,0);
  5666         this._start = this._unit.parseFromObject(this._params.startsOn);
  3119 var H=[C.elmt,S.elmt,F.elmt];
  5667     } else if ("endsOn" in this._params) {
  3120 var Q=this;
  5668         this._start = this._unit.parseFromObject(this._params.endsOn);
  3121 var L=function(c,d,e){return Q._onClickInstantEvent(C.elmt,d,P);
  5669         this.shiftPixels(-this._timeline.getPixelLength());
  3122 };
  5670     } else if ("centersOn" in this._params) {
  3123 SimileAjax.DOM.registerEvent(C.elmt,"mousedown",L);
  5671         this._start = this._unit.parseFromObject(this._params.centersOn);
  3124 SimileAjax.DOM.registerEvent(F.elmt,"mousedown",L);
  5672         this.shiftPixels(-this._timeline.getPixelLength() / 2);
  3125 SimileAjax.DOM.registerEvent(S.elmt,"mousedown",L);
  5673     } else {
  3126 var I=this._createHighlightDiv(V,C,Y,P);
  5674         this._start = this._unit.makeDefaultValue();
  3127 if(I!=null){H.push(I);
  5675         this.shiftPixels(-this._timeline.getPixelLength() / 2);
  3128 }this._fireEventPaintListeners("paintedEvent",P,H);
  5676     }
  3129 this._eventIdToElmt[P.getID()]=C.elmt;
  5677 };
  3130 this._tracks[R]=M;
  5678 
  3131 };
  5679 Timeline.HotZoneEther.prototype.setDate = function(date) {
  3132 Timeline.OriginalEventPainter.prototype.paintPreciseDurationEvent=function(L,P,T,R){var W=this._timeline.getDocument();
  5680     this._start = this._unit.cloneValue(date);
  3133 var K=L.getText();
  5681 };
  3134 var E=L.getStart();
  5682 
  3135 var S=L.getEnd();
  5683 Timeline.HotZoneEther.prototype.shiftPixels = function(pixels) {
  3136 var B=Math.round(this._band.dateToPixelOffset(E));
  5684     this._start = this.pixelOffsetToDate(pixels);
  3137 var A=Math.round(this._band.dateToPixelOffset(S));
  5685 };
  3138 var H=this._getLabelDivClassName(L);
  5686 
  3139 var I=this._frc.computeSize(K,H);
  5687 Timeline.HotZoneEther.prototype.dateToPixelOffset = function(date) {
  3140 var X=B;
  5688     return this._dateDiffToPixelOffset(this._start, date);
  3141 var C=X+I.width;
  5689 };
  3142 var V=Math.max(C,A);
  5690 
  3143 var N=this._findFreeTrack(L,V);
  5691 Timeline.HotZoneEther.prototype.pixelOffsetToDate = function(pixels) {
  3144 var U=Math.round(P.trackOffset+N*P.trackIncrement+T.event.tape.height);
  5692     return this._pixelOffsetToDate(pixels, this._start);
  3145 var Q=L.getColor();
  5693 };
  3146 Q=Q!=null?Q:T.event.duration.color;
  5694 
  3147 var D=this._paintEventTape(L,N,B,A,Q,100,P,T,0);
  5695 Timeline.HotZoneEther.prototype.zoom = function(zoomIn) {
  3148 var O=this._paintEventLabel(L,K,X,U,I.width,I.height,T,H,R);
  5696   var netIntervalChange = 0;
  3149 var F=[D.elmt,O.elmt];
  5697   var currentZoomIndex = this._band._zoomIndex;
  3150 var M=this;
  5698   var newZoomIndex = currentZoomIndex;
  3151 var J=function(Y,Z,a){return M._onClickDurationEvent(D.elmt,Z,L);
  5699 
  3152 };
  5700   if (zoomIn && (currentZoomIndex > 0)) {
  3153 SimileAjax.DOM.registerEvent(D.elmt,"mousedown",J);
  5701     newZoomIndex = currentZoomIndex - 1;
  3154 SimileAjax.DOM.registerEvent(O.elmt,"mousedown",J);
  5702   }
  3155 var G=this._createHighlightDiv(R,D,T,L);
  5703 
  3156 if(G!=null){F.push(G);
  5704   if (!zoomIn && (currentZoomIndex < (this._band._zoomSteps.length - 1))) {
  3157 }this._fireEventPaintListeners("paintedEvent",L,F);
  5705     newZoomIndex = currentZoomIndex + 1;
  3158 this._eventIdToElmt[L.getID()]=D.elmt;
  5706   }
  3159 this._tracks[N]=B;
  5707 
  3160 };
  5708   this._band._zoomIndex = newZoomIndex;
  3161 Timeline.OriginalEventPainter.prototype.paintImpreciseDurationEvent=function(N,S,Y,V){var b=this._timeline.getDocument();
  5709   this._interval =
  3162 var M=N.getText();
  5710     SimileAjax.DateTime.gregorianUnitLengths[this._band._zoomSteps[newZoomIndex].unit];
  3163 var E=N.getStart();
  5711   this._pixelsPerInterval = this._band._zoomSteps[newZoomIndex].pixelsPerInterval;
  3164 var T=N.getLatestStart();
  5712   netIntervalChange = this._band._zoomSteps[newZoomIndex].unit -
  3165 var W=N.getEnd();
  5713     this._band._zoomSteps[currentZoomIndex].unit;
  3166 var a=N.getEarliestEnd();
  5714 
  3167 var C=Math.round(this._band.dateToPixelOffset(E));
  5715   return netIntervalChange;
  3168 var G=Math.round(this._band.dateToPixelOffset(T));
  5716 };
  3169 var A=Math.round(this._band.dateToPixelOffset(W));
  5717 
  3170 var H=Math.round(this._band.dateToPixelOffset(a));
  5718 Timeline.HotZoneEther.prototype._dateDiffToPixelOffset = function(fromDate, toDate) {
  3171 var J=this._getLabelDivClassName(N);
  5719     var scale = this._getScale();
  3172 var K=this._frc.computeSize(M,J);
  5720     var fromTime = fromDate;
  3173 var c=G;
  5721     var toTime = toDate;
  3174 var B=c+K.width;
  5722 
  3175 var Z=Math.max(B,A);
  5723     var pixels = 0;
  3176 var P=this._findFreeTrack(N,Z);
  5724     if (this._unit.compare(fromTime, toTime) < 0) {
  3177 var X=Math.round(S.trackOffset+P*S.trackIncrement+Y.event.tape.height);
  5725         var z = 0;
  3178 var U=N.getColor();
  5726         while (z < this._zones.length) {
  3179 U=U!=null?U:Y.event.duration.color;
  5727             if (this._unit.compare(fromTime, this._zones[z].endTime) < 0) {
  3180 var R=this._paintEventTape(N,P,C,A,Y.event.duration.impreciseColor,Y.event.duration.impreciseOpacity,S,Y,0);
  5728                 break;
  3181 var D=this._paintEventTape(N,P,G,H,U,100,S,Y,1);
  5729             }
  3182 var Q=this._paintEventLabel(N,M,c,X,K.width,K.height,Y,J,V);
  5730             z++;
  3183 var F=[R.elmt,D.elmt,Q.elmt];
  5731         }
  3184 var O=this;
  5732 
  3185 var L=function(d,e,f){return O._onClickDurationEvent(D.elmt,e,N);
  5733         while (this._unit.compare(fromTime, toTime) < 0) {
  3186 };
  5734             var zone = this._zones[z];
  3187 SimileAjax.DOM.registerEvent(D.elmt,"mousedown",L);
  5735             var toTime2 = this._unit.earlier(toTime, zone.endTime);
  3188 SimileAjax.DOM.registerEvent(Q.elmt,"mousedown",L);
  5736 
  3189 var I=this._createHighlightDiv(V,D,Y,N);
  5737             pixels += (this._unit.compare(toTime2, fromTime) / (scale / zone.magnify));
  3190 if(I!=null){F.push(I);
  5738 
  3191 }this._fireEventPaintListeners("paintedEvent",N,F);
  5739             fromTime = toTime2;
  3192 this._eventIdToElmt[N.getID()]=D.elmt;
  5740             z++;
  3193 this._tracks[P]=C;
  5741         }
  3194 };
  5742     } else {
  3195 Timeline.OriginalEventPainter.prototype._encodeEventElID=function(B,A){return Timeline.EventUtils.encodeEventElID(this._timeline,this._band,B,A);
  5743         var z = this._zones.length - 1;
  3196 };
  5744         while (z >= 0) {
  3197 Timeline.OriginalEventPainter.prototype._findFreeTrack=function(E,A){var D=E.getTrackNum();
  5745             if (this._unit.compare(fromTime, this._zones[z].startTime) > 0) {
  3198 if(D!=null){return D;
  5746                 break;
  3199 }for(var C=0;
  5747             }
  3200 C<this._tracks.length;
  5748             z--;
  3201 C++){var B=this._tracks[C];
  5749         }
  3202 if(B>A){break;
  5750 
  3203 }}return C;
  5751         while (this._unit.compare(fromTime, toTime) > 0) {
  3204 };
  5752             var zone = this._zones[z];
  3205 Timeline.OriginalEventPainter.prototype._paintEventIcon=function(J,F,B,G,E,C){var I=J.getIcon();
  5753             var toTime2 = this._unit.later(toTime, zone.startTime);
  3206 I=I!=null?I:G.icon;
  5754 
  3207 var H;
  5755             pixels += (this._unit.compare(toTime2, fromTime) / (scale / zone.magnify));
  3208 if(C>0){H=G.trackOffset+F*G.trackIncrement+C+G.impreciseIconMargin;
  5756 
  3209 }else{var K=G.trackOffset+F*G.trackIncrement+G.trackHeight/2;
  5757             fromTime = toTime2;
  3210 H=Math.round(K-G.iconHeight/2);
  5758             z--;
  3211 }var D=SimileAjax.Graphics.createTranslucentImage(I);
  5759         }
  3212 var A=this._timeline.getDocument().createElement("div");
  5760     }
  3213 A.className=this._getElClassName("timeline-event-icon",J);
  5761     return pixels;
  3214 A.id=this._encodeEventElID("icon",J);
  5762 };
  3215 A.style.left=B+"px";
  5763 
  3216 A.style.top=H+"px";
  5764 Timeline.HotZoneEther.prototype._pixelOffsetToDate = function(pixels, fromDate) {
  3217 A.appendChild(D);
  5765     var scale = this._getScale();
  3218 if(J._title!=null){A.title=J._title;
  5766     var time = fromDate;
  3219 }this._eventLayer.appendChild(A);
  5767     if (pixels > 0) {
  3220 return{left:B,top:H,width:G.iconWidth,height:G.iconHeight,elmt:A};
  5768         var z = 0;
  3221 };
  5769         while (z < this._zones.length) {
  3222 Timeline.OriginalEventPainter.prototype._paintEventLabel=function(J,K,C,H,A,L,E,F,B){var I=this._timeline.getDocument();
  5770             if (this._unit.compare(time, this._zones[z].endTime) < 0) {
  3223 var G=I.createElement("div");
  5771                 break;
  3224 G.className=F;
  5772             }
  3225 G.id=this._encodeEventElID("label",J);
  5773             z++;
  3226 G.style.left=C+"px";
  5774         }
  3227 G.style.width=A+"px";
  5775 
  3228 G.style.top=H+"px";
  5776         while (pixels > 0) {
  3229 G.innerHTML=K;
  5777             var zone = this._zones[z];
  3230 if(J._title!=null){G.title=J._title;
  5778             var scale2 = scale / zone.magnify;
  3231 }var D=J.getTextColor();
  5779 
  3232 if(D==null){D=J.getColor();
  5780             if (zone.endTime == Number.POSITIVE_INFINITY) {
  3233 }if(D!=null){G.style.color=D;
  5781                 time = this._unit.change(time, pixels * scale2);
  3234 }if(E.event.highlightLabelBackground&&B>=0){G.style.background=this._getHighlightColor(B,E);
  5782                 pixels = 0;
  3235 }this._eventLayer.appendChild(G);
  5783             } else {
  3236 return{left:C,top:H,width:A,height:L,elmt:G};
  5784                 var pixels2 = this._unit.compare(zone.endTime, time) / scale2;
  3237 };
  5785                 if (pixels2 > pixels) {
  3238 Timeline.OriginalEventPainter.prototype._paintEventTape=function(N,I,F,A,C,H,J,G,O){var B=A-F;
  5786                     time = this._unit.change(time, pixels * scale2);
  3239 var E=G.event.tape.height;
  5787                     pixels = 0;
  3240 var K=J.trackOffset+I*J.trackIncrement;
  5788                 } else {
  3241 var M=this._timeline.getDocument().createElement("div");
  5789                     time = zone.endTime;
  3242 M.className=this._getElClassName("timeline-event-tape",N);
  5790                     pixels -= pixels2;
  3243 M.id=this._encodeEventElID("tape"+O,N);
  5791                 }
  3244 M.style.left=F+"px";
  5792             }
  3245 M.style.width=B+"px";
  5793             z++;
  3246 M.style.height=E+"px";
  5794         }
  3247 M.style.top=K+"px";
  5795     } else {
  3248 if(N._title!=null){M.title=N._title;
  5796         var z = this._zones.length - 1;
  3249 }if(C!=null){M.style.backgroundColor=C;
  5797         while (z >= 0) {
  3250 }var L=N.getTapeImage();
  5798             if (this._unit.compare(time, this._zones[z].startTime) > 0) {
  3251 var D=N.getTapeRepeat();
  5799                 break;
  3252 D=D!=null?D:"repeat";
  5800             }
  3253 if(L!=null){M.style.backgroundImage="url("+L+")";
  5801             z--;
  3254 M.style.backgroundRepeat=D;
  5802         }
  3255 }SimileAjax.Graphics.setOpacity(M,H);
  5803 
  3256 this._eventLayer.appendChild(M);
  5804         pixels = -pixels;
  3257 return{left:F,top:K,width:B,height:E,elmt:M};
  5805         while (pixels > 0) {
  3258 };
  5806             var zone = this._zones[z];
  3259 Timeline.OriginalEventPainter.prototype._getLabelDivClassName=function(A){return this._getElClassName("timeline-event-label",A);
  5807             var scale2 = scale / zone.magnify;
  3260 };
  5808 
  3261 Timeline.OriginalEventPainter.prototype._getElClassName=function(B,A){var C=A.getClassName();
  5809             if (zone.startTime == Number.NEGATIVE_INFINITY) {
  3262 return B+(C!=null?(" "+C):"");
  5810                 time = this._unit.change(time, -pixels * scale2);
  3263 };
  5811                 pixels = 0;
  3264 Timeline.OriginalEventPainter.prototype._getHighlightColor=function(A,C){var B=C.event.highlightColors;
  5812             } else {
  3265 return B[Math.min(A,B.length-1)];
  5813                 var pixels2 = this._unit.compare(time, zone.startTime) / scale2;
  3266 };
  5814                 if (pixels2 > pixels) {
  3267 Timeline.OriginalEventPainter.prototype._createHighlightDiv=function(A,D,F,B){var G=null;
  5815                     time = this._unit.change(time, -pixels * scale2);
  3268 if(A>=0){var E=this._timeline.getDocument();
  5816                     pixels = 0;
  3269 var C=this._getHighlightColor(A,F);
  5817                 } else {
  3270 G=E.createElement("div");
  5818                     time = zone.startTime;
  3271 G.className=this._getElClassName("timeline-event-highlight",B);
  5819                     pixels -= pixels2;
  3272 G.id=this._encodeEventElID("highlight0",B);
  5820                 }
  3273 G.style.position="absolute";
  5821             }
  3274 G.style.overflow="hidden";
  5822             z--;
  3275 G.style.left=(D.left-2)+"px";
  5823         }
  3276 G.style.width=(D.width+4)+"px";
  5824     }
  3277 G.style.top=(D.top-2)+"px";
  5825     return time;
  3278 G.style.height=(D.height+4)+"px";
  5826 };
  3279 G.style.background=C;
  5827 
  3280 this._highlightLayer.appendChild(G);
  5828 Timeline.HotZoneEther.prototype._getScale = function() {
  3281 }return G;
  5829     return this._interval / this._pixelsPerInterval;
  3282 };
  5830 };
  3283 Timeline.OriginalEventPainter.prototype._onClickInstantEvent=function(B,C,A){var D=SimileAjax.DOM.getPageCoordinates(B);
  5831 /*==================================================
  3284 this._showBubble(D.left+Math.ceil(B.offsetWidth/2),D.top+Math.ceil(B.offsetHeight/2),A);
  5832  *  Gregorian Ether Painter
  3285 this._fireOnSelect(A.getID());
  5833  *==================================================
  3286 C.cancelBubble=true;
  5834  */
  3287 SimileAjax.DOM.cancelEvent(C);
  5835 
  3288 return false;
  5836 Timeline.GregorianEtherPainter = function(params) {
  3289 };
  5837     this._params = params;
  3290 Timeline.OriginalEventPainter.prototype._onClickDurationEvent=function(D,C,B){if("pageX" in C){var A=C.pageX;
  5838     this._theme = params.theme;
  3291 var F=C.pageY;
  5839     this._unit = params.unit;
  3292 }else{var E=SimileAjax.DOM.getPageCoordinates(D);
  5840     this._multiple = ("multiple" in params) ? params.multiple : 1;
  3293 var A=C.offsetX+E.left;
  5841 };
  3294 var F=C.offsetY+E.top;
  5842 
  3295 }this._showBubble(A,F,B);
  5843 Timeline.GregorianEtherPainter.prototype.initialize = function(band, timeline) {
  3296 this._fireOnSelect(B.getID());
  5844     this._band = band;
  3297 C.cancelBubble=true;
  5845     this._timeline = timeline;
  3298 SimileAjax.DOM.cancelEvent(C);
  5846 
  3299 return false;
  5847     this._backgroundLayer = band.createLayerDiv(0);
  3300 };
  5848     this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
  3301 Timeline.OriginalEventPainter.prototype.showBubble=function(A){var B=this._eventIdToElmt[A.getID()];
  5849     this._backgroundLayer.className = 'timeline-ether-bg';
  3302 if(B){var C=SimileAjax.DOM.getPageCoordinates(B);
  5850   //  this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
  3303 this._showBubble(C.left+B.offsetWidth/2,C.top+B.offsetHeight/2,A);
  5851 
  3304 }};
  5852 
  3305 Timeline.OriginalEventPainter.prototype._showBubble=function(A,E,B){var D=document.createElement("div");
  5853     this._markerLayer = null;
  3306 var C=this._params.theme.event.bubble;
  5854     this._lineLayer = null;
  3307 B.fillInfoBubble(D,this._params.theme,this._band.getLabeller());
  5855 
  3308 SimileAjax.WindowManager.cancelPopups();
  5856     var align = ("align" in this._params && this._params.align != undefined) ? this._params.align :
  3309 SimileAjax.Graphics.createBubbleForContentAndPoint(D,A,E,C.width,null,C.maxHeight);
  5857         this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
  3310 };
  5858     var showLine = ("showLine" in this._params) ? this._params.showLine :
  3311 Timeline.OriginalEventPainter.prototype._fireOnSelect=function(B){for(var A=0;
  5859         this._theme.ether.interval.line.show;
  3312 A<this._onSelectListeners.length;
  5860 
  3313 A++){this._onSelectListeners[A](B);
  5861     this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
  3314 }};
  5862         this._timeline, this._band, this._theme, align, showLine);
  3315 Timeline.OriginalEventPainter.prototype._fireEventPaintListeners=function(D,A,C){for(var B=0;
  5863 
  3316 B<this._eventPaintListeners.length;
  5864     this._highlight = new Timeline.EtherHighlight(
  3317 B++){this._eventPaintListeners[B](this._band,D,A,C);
  5865         this._timeline, this._band, this._theme, this._backgroundLayer);
  3318 }};
  5866 }
  3319 
  5867 
  3320 
  5868 Timeline.GregorianEtherPainter.prototype.setHighlight = function(startDate, endDate) {
  3321 /* overview-painter.js */
  5869     this._highlight.position(startDate, endDate);
  3322 Timeline.OverviewEventPainter=function(A){this._params=A;
  5870 }
  3323 this._onSelectListeners=[];
  5871 
  3324 this._filterMatcher=null;
  5872 Timeline.GregorianEtherPainter.prototype.paint = function() {
  3325 this._highlightMatcher=null;
  5873     if (this._markerLayer) {
  3326 };
  5874         this._band.removeLayerDiv(this._markerLayer);
  3327 Timeline.OverviewEventPainter.prototype.initialize=function(B,A){this._band=B;
  5875     }
  3328 this._timeline=A;
  5876     this._markerLayer = this._band.createLayerDiv(100);
  3329 this._eventLayer=null;
  5877     this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
  3330 this._highlightLayer=null;
  5878     this._markerLayer.style.display = "none";
  3331 };
  5879 
  3332 Timeline.OverviewEventPainter.prototype.getType=function(){return"overview";
  5880     if (this._lineLayer) {
  3333 };
  5881         this._band.removeLayerDiv(this._lineLayer);
  3334 Timeline.OverviewEventPainter.prototype.addOnSelectListener=function(A){this._onSelectListeners.push(A);
  5882     }
  3335 };
  5883     this._lineLayer = this._band.createLayerDiv(1);
  3336 Timeline.OverviewEventPainter.prototype.removeOnSelectListener=function(B){for(var A=0;
  5884     this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
  3337 A<this._onSelectListeners.length;
  5885     this._lineLayer.style.display = "none";
  3338 A++){if(this._onSelectListeners[A]==B){this._onSelectListeners.splice(A,1);
  5886 
  3339 break;
  5887     var minDate = this._band.getMinDate();
  3340 }}};
  5888     var maxDate = this._band.getMaxDate();
  3341 Timeline.OverviewEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
  5889 
  3342 };
  5890     var timeZone = this._band.getTimeZone();
  3343 Timeline.OverviewEventPainter.prototype.setFilterMatcher=function(A){this._filterMatcher=A;
  5891     var labeller = this._band.getLabeller();
  3344 };
  5892 
  3345 Timeline.OverviewEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
  5893     SimileAjax.DateTime.roundDownToInterval(minDate, this._unit, timeZone, this._multiple, this._theme.firstDayOfWeek);
  3346 };
  5894 
  3347 Timeline.OverviewEventPainter.prototype.setHighlightMatcher=function(A){this._highlightMatcher=A;
  5895     var p = this;
  3348 };
  5896     var incrementDate = function(date) {
  3349 Timeline.OverviewEventPainter.prototype.paint=function(){var B=this._band.getEventSource();
  5897         for (var i = 0; i < p._multiple; i++) {
  3350 if(B==null){return ;
  5898             SimileAjax.DateTime.incrementByInterval(date, p._unit);
  3351 }this._prepareForPainting();
  5899         }
  3352 var H=this._params.theme.event;
  5900     };
  3353 var F={trackOffset:H.overviewTrack.offset,trackHeight:H.overviewTrack.height,trackGap:H.overviewTrack.gap,trackIncrement:H.overviewTrack.height+H.overviewTrack.gap};
  5901 
  3354 var C=this._band.getMinDate();
  5902     while (minDate.getTime() < maxDate.getTime()) {
  3355 var A=this._band.getMaxDate();
  5903         this._intervalMarkerLayout.createIntervalMarker(
  3356 var I=(this._filterMatcher!=null)?this._filterMatcher:function(J){return true;
  5904             minDate, labeller, this._unit, this._markerLayer, this._lineLayer);
  3357 };
  5905 
  3358 var E=(this._highlightMatcher!=null)?this._highlightMatcher:function(J){return -1;
  5906         incrementDate(minDate);
  3359 };
  5907     }
  3360 var D=B.getEventReverseIterator(C,A);
  5908     this._markerLayer.style.display = "block";
  3361 while(D.hasNext()){var G=D.next();
  5909     this._lineLayer.style.display = "block";
  3362 if(I(G)){this.paintEvent(G,F,this._params.theme,E(G));
  5910 };
  3363 }}this._highlightLayer.style.display="block";
  5911 
  3364 this._eventLayer.style.display="block";
  5912 Timeline.GregorianEtherPainter.prototype.softPaint = function() {
  3365 this._band.updateEventTrackInfo(this._tracks.length,F.trackIncrement);
  5913 };
  3366 };
  5914 
  3367 Timeline.OverviewEventPainter.prototype.softPaint=function(){};
  5915 Timeline.GregorianEtherPainter.prototype.zoom = function(netIntervalChange) {
  3368 Timeline.OverviewEventPainter.prototype._prepareForPainting=function(){var A=this._band;
  5916   if (netIntervalChange != 0) {
  3369 this._tracks=[];
  5917     this._unit += netIntervalChange;
  3370 if(this._highlightLayer!=null){A.removeLayerDiv(this._highlightLayer);
  5918   }
  3371 }this._highlightLayer=A.createLayerDiv(105,"timeline-band-highlights");
  5919 };
  3372 this._highlightLayer.style.display="none";
  5920 
  3373 if(this._eventLayer!=null){A.removeLayerDiv(this._eventLayer);
  5921 
  3374 }this._eventLayer=A.createLayerDiv(110,"timeline-band-events");
  5922 /*==================================================
  3375 this._eventLayer.style.display="none";
  5923  *  Hot Zone Gregorian Ether Painter
  3376 };
  5924  *==================================================
  3377 Timeline.OverviewEventPainter.prototype.paintEvent=function(B,C,D,A){if(B.isInstant()){this.paintInstantEvent(B,C,D,A);
  5925  */
  3378 }else{this.paintDurationEvent(B,C,D,A);
  5926 
  3379 }};
  5927 Timeline.HotZoneGregorianEtherPainter = function(params) {
  3380 Timeline.OverviewEventPainter.prototype.paintInstantEvent=function(C,F,G,B){var A=C.getStart();
  5928     this._params = params;
  3381 var H=Math.round(this._band.dateToPixelOffset(A));
  5929     this._theme = params.theme;
  3382 var D=C.getColor();
  5930 
  3383 D=D!=null?D:G.event.duration.color;
  5931     this._zones = [{
  3384 var E=this._paintEventTick(C,H,D,100,F,G);
  5932         startTime:  Number.NEGATIVE_INFINITY,
  3385 this._createHighlightDiv(B,E,G);
  5933         endTime:    Number.POSITIVE_INFINITY,
  3386 };
  5934         unit:       params.unit,
  3387 Timeline.OverviewEventPainter.prototype.paintDurationEvent=function(K,J,I,D){var A=K.getLatestStart();
  5935         multiple:   1
  3388 var C=K.getEarliestEnd();
  5936     }];
  3389 var B=Math.round(this._band.dateToPixelOffset(A));
  5937     for (var i = 0; i < params.zones.length; i++) {
  3390 var E=Math.round(this._band.dateToPixelOffset(C));
  5938         var zone = params.zones[i];
  3391 var H=0;
  5939         var zoneStart = SimileAjax.DateTime.parseGregorianDateTime(zone.start).getTime();
  3392 for(;
  5940         var zoneEnd = SimileAjax.DateTime.parseGregorianDateTime(zone.end).getTime();
  3393 H<this._tracks.length;
  5941 
  3394 H++){if(E<this._tracks[H]){break;
  5942         for (var j = 0; j < this._zones.length && zoneEnd > zoneStart; j++) {
  3395 }}this._tracks[H]=E;
  5943             var zone2 = this._zones[j];
  3396 var G=K.getColor();
  5944 
  3397 G=G!=null?G:I.event.duration.color;
  5945             if (zoneStart < zone2.endTime) {
  3398 var F=this._paintEventTape(K,H,B,E,G,100,J,I);
  5946                 if (zoneStart > zone2.startTime) {
  3399 this._createHighlightDiv(D,F,I);
  5947                     this._zones.splice(j, 0, {
  3400 };
  5948                         startTime:   zone2.startTime,
  3401 Timeline.OverviewEventPainter.prototype._paintEventTape=function(K,B,C,J,D,F,G,E){var H=G.trackOffset+B*G.trackIncrement;
  5949                         endTime:     zoneStart,
  3402 var A=J-C;
  5950                         unit:        zone2.unit,
  3403 var L=G.trackHeight;
  5951                         multiple:    zone2.multiple
  3404 var I=this._timeline.getDocument().createElement("div");
  5952                     });
  3405 I.className="timeline-small-event-tape";
  5953                     j++;
  3406 I.style.left=C+"px";
  5954 
  3407 I.style.width=A+"px";
  5955                     zone2.startTime = zoneStart;
  3408 I.style.top=H+"px";
  5956                 }
  3409 I.style.height=L+"px";
  5957 
  3410 if(D!=null){I.style.backgroundColor=D;
  5958                 if (zoneEnd < zone2.endTime) {
  3411 }if(F<100){SimileAjax.Graphics.setOpacity(I,F);
  5959                     this._zones.splice(j, 0, {
  3412 }this._eventLayer.appendChild(I);
  5960                         startTime:  zoneStart,
  3413 return{left:C,top:H,width:A,height:L,elmt:I};
  5961                         endTime:    zoneEnd,
  3414 };
  5962                         unit:       zone.unit,
  3415 Timeline.OverviewEventPainter.prototype._paintEventTick=function(J,B,D,F,G,E){var K=E.event.overviewTrack.tickHeight;
  5963                         multiple:   (zone.multiple) ? zone.multiple : 1
  3416 var H=G.trackOffset-K;
  5964                     });
  3417 var A=1;
  5965                     j++;
  3418 var I=this._timeline.getDocument().createElement("div");
  5966 
  3419 I.className="timeline-small-event-icon";
  5967                     zone2.startTime = zoneEnd;
  3420 I.style.left=B+"px";
  5968                     zoneStart = zoneEnd;
  3421 I.style.top=H+"px";
  5969                 } else {
  3422 var C=J.getClassName();
  5970                     zone2.multiple = zone.multiple;
  3423 if(C){I.className+=" small-"+C;
  5971                     zone2.unit = zone.unit;
  3424 }if(F<100){SimileAjax.Graphics.setOpacity(I,F);
  5972                     zoneStart = zone2.endTime;
  3425 }this._eventLayer.appendChild(I);
  5973                 }
  3426 return{left:B,top:H,width:A,height:K,elmt:I};
  5974             } // else, try the next existing zone
  3427 };
  5975         }
  3428 Timeline.OverviewEventPainter.prototype._createHighlightDiv=function(A,C,E){if(A>=0){var D=this._timeline.getDocument();
  5976     }
  3429 var G=E.event;
  5977 };
  3430 var B=G.highlightColors[Math.min(A,G.highlightColors.length-1)];
  5978 
  3431 var F=D.createElement("div");
  5979 Timeline.HotZoneGregorianEtherPainter.prototype.initialize = function(band, timeline) {
  3432 F.style.position="absolute";
  5980     this._band = band;
  3433 F.style.overflow="hidden";
  5981     this._timeline = timeline;
  3434 F.style.left=(C.left-1)+"px";
  5982 
  3435 F.style.width=(C.width+2)+"px";
  5983     this._backgroundLayer = band.createLayerDiv(0);
  3436 F.style.top=(C.top-1)+"px";
  5984     this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
  3437 F.style.height=(C.height+2)+"px";
  5985     this._backgroundLayer.className ='timeline-ether-bg';
  3438 F.style.background=B;
  5986     //this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
  3439 this._highlightLayer.appendChild(F);
  5987 
  3440 }};
  5988     this._markerLayer = null;
  3441 Timeline.OverviewEventPainter.prototype.showBubble=function(A){};
  5989     this._lineLayer = null;
  3442 
  5990 
  3443 
  5991     var align = ("align" in this._params && this._params.align != undefined) ? this._params.align :
  3444 /* sources.js */
  5992         this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
  3445 Timeline.DefaultEventSource=function(A){this._events=(A instanceof Object)?A:new SimileAjax.EventIndex();
  5993     var showLine = ("showLine" in this._params) ? this._params.showLine :
  3446 this._listeners=[];
  5994         this._theme.ether.interval.line.show;
  3447 };
  5995 
  3448 Timeline.DefaultEventSource.prototype.addListener=function(A){this._listeners.push(A);
  5996     this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
  3449 };
  5997         this._timeline, this._band, this._theme, align, showLine);
  3450 Timeline.DefaultEventSource.prototype.removeListener=function(B){for(var A=0;
  5998 
  3451 A<this._listeners.length;
  5999     this._highlight = new Timeline.EtherHighlight(
  3452 A++){if(this._listeners[A]==B){this._listeners.splice(A,1);
  6000         this._timeline, this._band, this._theme, this._backgroundLayer);
  3453 break;
  6001 }
  3454 }}};
  6002 
  3455 Timeline.DefaultEventSource.prototype.loadXML=function(G,A){var C=this._getBaseURL(A);
  6003 Timeline.HotZoneGregorianEtherPainter.prototype.setHighlight = function(startDate, endDate) {
  3456 var H=G.documentElement.getAttribute("wiki-url");
  6004     this._highlight.position(startDate, endDate);
  3457 var L=G.documentElement.getAttribute("wiki-section");
  6005 }
  3458 var E=G.documentElement.getAttribute("date-time-format");
  6006 
  3459 var F=this._events.getUnit().getParser(E);
  6007 Timeline.HotZoneGregorianEtherPainter.prototype.paint = function() {
  3460 var D=G.documentElement.firstChild;
  6008     if (this._markerLayer) {
  3461 var I=false;
  6009         this._band.removeLayerDiv(this._markerLayer);
  3462 while(D!=null){if(D.nodeType==1){var K="";
  6010     }
  3463 if(D.firstChild!=null&&D.firstChild.nodeType==3){K=D.firstChild.nodeValue;
  6011     this._markerLayer = this._band.createLayerDiv(100);
  3464 }var B=(D.getAttribute("isDuration")===null&&D.getAttribute("durationEvent")===null)||D.getAttribute("isDuration")=="false"||D.getAttribute("durationEvent")=="false";
  6012     this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
  3465 var J=new Timeline.DefaultEventSource.Event({id:D.getAttribute("id"),start:F(D.getAttribute("start")),end:F(D.getAttribute("end")),latestStart:F(D.getAttribute("latestStart")),earliestEnd:F(D.getAttribute("earliestEnd")),instant:B,text:D.getAttribute("title"),description:K,image:this._resolveRelativeURL(D.getAttribute("image"),C),link:this._resolveRelativeURL(D.getAttribute("link"),C),icon:this._resolveRelativeURL(D.getAttribute("icon"),C),color:D.getAttribute("color"),textColor:D.getAttribute("textColor"),hoverText:D.getAttribute("hoverText"),classname:D.getAttribute("classname"),tapeImage:D.getAttribute("tapeImage"),tapeRepeat:D.getAttribute("tapeRepeat"),caption:D.getAttribute("caption"),eventID:D.getAttribute("eventID"),trackNum:D.getAttribute("trackNum")});
  6013     this._markerLayer.style.display = "none";
  3466 J._node=D;
  6014 
  3467 J.getProperty=function(M){return this._node.getAttribute(M);
  6015     if (this._lineLayer) {
  3468 };
  6016         this._band.removeLayerDiv(this._lineLayer);
  3469 J.setWikiInfo(H,L);
  6017     }
  3470 this._events.add(J);
  6018     this._lineLayer = this._band.createLayerDiv(1);
  3471 I=true;
  6019     this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
  3472 }D=D.nextSibling;
  6020     this._lineLayer.style.display = "none";
  3473 }if(I){this._fire("onAddMany",[]);
  6021 
  3474 }};
  6022     var minDate = this._band.getMinDate();
  3475 Timeline.DefaultEventSource.prototype.loadJSON=function(G,B){var D=this._getBaseURL(B);
  6023     var maxDate = this._band.getMaxDate();
  3476 var J=false;
  6024 
  3477 if(G&&G.events){var I=("wikiURL" in G)?G.wikiURL:null;
  6025     var timeZone = this._band.getTimeZone();
  3478 var L=("wikiSection" in G)?G.wikiSection:null;
  6026     var labeller = this._band.getLabeller();
  3479 var E=("dateTimeFormat" in G)?G.dateTimeFormat:null;
  6027 
  3480 var H=this._events.getUnit().getParser(E);
  6028     var p = this;
  3481 for(var F=0;
  6029     var incrementDate = function(date, zone) {
  3482 F<G.events.length;
  6030         for (var i = 0; i < zone.multiple; i++) {
  3483 F++){var A=G.events[F];
  6031             SimileAjax.DateTime.incrementByInterval(date, zone.unit);
  3484 var C=A.isDuration||(A.durationEvent!=null&&!A.durationEvent);
  6032         }
  3485 var K=new Timeline.DefaultEventSource.Event({id:("id" in A)?A.id:undefined,start:H(A.start),end:H(A.end),latestStart:H(A.latestStart),earliestEnd:H(A.earliestEnd),instant:C,text:A.title,description:A.description,image:this._resolveRelativeURL(A.image,D),link:this._resolveRelativeURL(A.link,D),icon:this._resolveRelativeURL(A.icon,D),color:A.color,textColor:A.textColor,hoverText:A.hoverText,classname:A.classname,tapeImage:A.tapeImage,tapeRepeat:A.tapeRepeat,caption:A.caption,eventID:A.eventID,trackNum:A.trackNum});
  6033     };
  3486 K._obj=A;
  6034 
  3487 K.getProperty=function(M){return this._obj[M];
  6035     var zStart = 0;
  3488 };
  6036     while (zStart < this._zones.length) {
  3489 K.setWikiInfo(I,L);
  6037         if (minDate.getTime() < this._zones[zStart].endTime) {
  3490 this._events.add(K);
  6038             break;
  3491 J=true;
  6039         }
  3492 }}if(J){this._fire("onAddMany",[]);
  6040         zStart++;
  3493 }};
  6041     }
  3494 Timeline.DefaultEventSource.prototype.loadSPARQL=function(H,A){var D=this._getBaseURL(A);
  6042     var zEnd = this._zones.length - 1;
  3495 var F="iso8601";
  6043     while (zEnd >= 0) {
  3496 var G=this._events.getUnit().getParser(F);
  6044         if (maxDate.getTime() > this._zones[zEnd].startTime) {
  3497 if(H==null){return ;
  6045             break;
  3498 }var E=H.documentElement.firstChild;
  6046         }
  3499 while(E!=null&&(E.nodeType!=1||E.nodeName!="results")){E=E.nextSibling;
  6047         zEnd--;
  3500 }var J=null;
  6048     }
  3501 var M=null;
  6049 
  3502 if(E!=null){J=E.getAttribute("wiki-url");
  6050     for (var z = zStart; z <= zEnd; z++) {
  3503 M=E.getAttribute("wiki-section");
  6051         var zone = this._zones[z];
  3504 E=E.firstChild;
  6052 
  3505 }var K=false;
  6053         var minDate2 = new Date(Math.max(minDate.getTime(), zone.startTime));
  3506 while(E!=null){if(E.nodeType==1){var C={};
  6054         var maxDate2 = new Date(Math.min(maxDate.getTime(), zone.endTime));
  3507 var I=E.firstChild;
  6055 
  3508 while(I!=null){if(I.nodeType==1&&I.firstChild!=null&&I.firstChild.nodeType==1&&I.firstChild.firstChild!=null&&I.firstChild.firstChild.nodeType==3){C[I.getAttribute("name")]=I.firstChild.firstChild.nodeValue;
  6056         SimileAjax.DateTime.roundDownToInterval(minDate2, zone.unit, timeZone, zone.multiple, this._theme.firstDayOfWeek);
  3509 }I=I.nextSibling;
  6057         SimileAjax.DateTime.roundUpToInterval(maxDate2, zone.unit, timeZone, zone.multiple, this._theme.firstDayOfWeek);
  3510 }if(C["start"]==null&&C["date"]!=null){C["start"]=C["date"];
  6058 
  3511 }var B=(C["isDuration"]===null&&C["durationEvent"]===null)||C["isDuration"]=="false"||C["durationEvent"]=="false";
  6059         while (minDate2.getTime() < maxDate2.getTime()) {
  3512 var L=new Timeline.DefaultEventSource.Event({id:C["id"],start:G(C["start"]),end:G(C["end"]),latestStart:G(C["latestStart"]),earliestEnd:G(C["earliestEnd"]),instant:B,text:C["title"],description:C["description"],image:this._resolveRelativeURL(C["image"],D),link:this._resolveRelativeURL(C["link"],D),icon:this._resolveRelativeURL(C["icon"],D),color:C["color"],textColor:C["textColor"],hoverText:C["hoverText"],caption:C["caption"],classname:C["classname"],tapeImage:C["tapeImage"],tapeRepeat:C["tapeRepeat"],eventID:C["eventID"],trackNum:C["trackNum"]});
  6060             this._intervalMarkerLayout.createIntervalMarker(
  3513 L._bindings=C;
  6061                 minDate2, labeller, zone.unit, this._markerLayer, this._lineLayer);
  3514 L.getProperty=function(N){return this._bindings[N];
  6062 
  3515 };
  6063             incrementDate(minDate2, zone);
  3516 L.setWikiInfo(J,M);
  6064         }
  3517 this._events.add(L);
  6065     }
  3518 K=true;
  6066     this._markerLayer.style.display = "block";
  3519 }E=E.nextSibling;
  6067     this._lineLayer.style.display = "block";
  3520 }if(K){this._fire("onAddMany",[]);
  6068 };
  3521 }};
  6069 
  3522 Timeline.DefaultEventSource.prototype.add=function(A){this._events.add(A);
  6070 Timeline.HotZoneGregorianEtherPainter.prototype.softPaint = function() {
  3523 this._fire("onAddOne",[A]);
  6071 };
  3524 };
  6072 
  3525 Timeline.DefaultEventSource.prototype.addMany=function(B){for(var A=0;
  6073 Timeline.HotZoneGregorianEtherPainter.prototype.zoom = function(netIntervalChange) {
  3526 A<B.length;
  6074   if (netIntervalChange != 0) {
  3527 A++){this._events.add(B[A]);
  6075     for (var i = 0; i < this._zones.length; ++i) {
  3528 }this._fire("onAddMany",[]);
  6076       if (this._zones[i]) {
  3529 };
  6077         this._zones[i].unit += netIntervalChange;
  3530 Timeline.DefaultEventSource.prototype.clear=function(){this._events.removeAll();
  6078       }
  3531 this._fire("onClear",[]);
  6079     }
  3532 };
  6080   }
  3533 Timeline.DefaultEventSource.prototype.getEvent=function(A){return this._events.getEvent(A);
  6081 };
  3534 };
  6082 
  3535 Timeline.DefaultEventSource.prototype.getEventIterator=function(A,B){return this._events.getIterator(A,B);
  6083 /*==================================================
  3536 };
  6084  *  Year Count Ether Painter
  3537 Timeline.DefaultEventSource.prototype.getEventReverseIterator=function(A,B){return this._events.getReverseIterator(A,B);
  6085  *==================================================
  3538 };
  6086  */
  3539 Timeline.DefaultEventSource.prototype.getAllEventIterator=function(){return this._events.getAllIterator();
  6087 
  3540 };
  6088 Timeline.YearCountEtherPainter = function(params) {
  3541 Timeline.DefaultEventSource.prototype.getCount=function(){return this._events.getCount();
  6089     this._params = params;
  3542 };
  6090     this._theme = params.theme;
  3543 Timeline.DefaultEventSource.prototype.getEarliestDate=function(){return this._events.getEarliestDate();
  6091     this._startDate = SimileAjax.DateTime.parseGregorianDateTime(params.startDate);
  3544 };
  6092     this._multiple = ("multiple" in params) ? params.multiple : 1;
  3545 Timeline.DefaultEventSource.prototype.getLatestDate=function(){return this._events.getLatestDate();
  6093 };
  3546 };
  6094 
  3547 Timeline.DefaultEventSource.prototype._fire=function(B,A){for(var C=0;
  6095 Timeline.YearCountEtherPainter.prototype.initialize = function(band, timeline) {
  3548 C<this._listeners.length;
  6096     this._band = band;
  3549 C++){var D=this._listeners[C];
  6097     this._timeline = timeline;
  3550 if(B in D){try{D[B].apply(D,A);
  6098 
  3551 }catch(E){SimileAjax.Debug.exception(E);
  6099     this._backgroundLayer = band.createLayerDiv(0);
  3552 }}}};
  6100     this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
  3553 Timeline.DefaultEventSource.prototype._getBaseURL=function(A){if(A.indexOf("://")<0){var C=this._getBaseURL(document.location.href);
  6101     this._backgroundLayer.className = 'timeline-ether-bg';
  3554 if(A.substr(0,1)=="/"){A=C.substr(0,C.indexOf("/",C.indexOf("://")+3))+A;
  6102    // this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
  3555 }else{A=C+A;
  6103 
  3556 }}var B=A.lastIndexOf("/");
  6104     this._markerLayer = null;
  3557 if(B<0){return"";
  6105     this._lineLayer = null;
  3558 }else{return A.substr(0,B+1);
  6106 
  3559 }};
  6107     var align = ("align" in this._params) ? this._params.align :
  3560 Timeline.DefaultEventSource.prototype._resolveRelativeURL=function(A,B){if(A==null||A==""){return A;
  6108         this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
  3561 }else{if(A.indexOf("://")>0){return A;
  6109     var showLine = ("showLine" in this._params) ? this._params.showLine :
  3562 }else{if(A.substr(0,1)=="/"){return B.substr(0,B.indexOf("/",B.indexOf("://")+3))+A;
  6110         this._theme.ether.interval.line.show;
  3563 }else{return B+A;
  6111 
  3564 }}}};
  6112     this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
  3565 Timeline.DefaultEventSource.Event=function(A){function D(E){return(A[E]!=null&&A[E]!="")?A[E]:null;
  6113         this._timeline, this._band, this._theme, align, showLine);
  3566 }var C=A.id?A.id.trim():"";
  6114 
  3567 this._id=C.length>0?C:Timeline.EventUtils.getNewEventID();
  6115     this._highlight = new Timeline.EtherHighlight(
  3568 this._instant=A.instant||(A.end==null);
  6116         this._timeline, this._band, this._theme, this._backgroundLayer);
  3569 this._start=A.start;
  6117 };
  3570 this._end=(A.end!=null)?A.end:A.start;
  6118 
  3571 this._latestStart=(A.latestStart!=null)?A.latestStart:(A.instant?this._end:this._start);
  6119 Timeline.YearCountEtherPainter.prototype.setHighlight = function(startDate, endDate) {
  3572 this._earliestEnd=(A.earliestEnd!=null)?A.earliestEnd:this._end;
  6120     this._highlight.position(startDate, endDate);
  3573 var B=[];
  6121 };
  3574 if(this._start>this._latestStart){this._latestStart=this._start;
  6122 
  3575 B.push("start is > latestStart");
  6123 Timeline.YearCountEtherPainter.prototype.paint = function() {
  3576 }if(this._start>this._earliestEnd){this._earliestEnd=this._latestStart;
  6124     if (this._markerLayer) {
  3577 B.push("start is > earliestEnd");
  6125         this._band.removeLayerDiv(this._markerLayer);
  3578 }if(this._start>this._end){this._end=this._earliestEnd;
  6126     }
  3579 B.push("start is > end");
  6127     this._markerLayer = this._band.createLayerDiv(100);
  3580 }if(this._latestStart>this._earliestEnd){this._earliestEnd=this._latestStart;
  6128     this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
  3581 B.push("latestStart is > earliestEnd");
  6129     this._markerLayer.style.display = "none";
  3582 }if(this._latestStart>this._end){this._end=this._earliestEnd;
  6130 
  3583 B.push("latestStart is > end");
  6131     if (this._lineLayer) {
  3584 }if(this._earliestEnd>this._end){this._end=this._earliestEnd;
  6132         this._band.removeLayerDiv(this._lineLayer);
  3585 B.push("earliestEnd is > end");
  6133     }
  3586 }this._eventID=D("eventID");
  6134     this._lineLayer = this._band.createLayerDiv(1);
  3587 this._text=(A.text!=null)?SimileAjax.HTML.deEntify(A.text):"";
  6135     this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
  3588 if(B.length>0){this._text+=" PROBLEM: "+B.join(", ");
  6136     this._lineLayer.style.display = "none";
  3589 }this._description=SimileAjax.HTML.deEntify(A.description);
  6137 
  3590 this._image=D("image");
  6138     var minDate = new Date(this._startDate.getTime());
  3591 this._link=D("link");
  6139     var maxDate = this._band.getMaxDate();
  3592 this._title=D("hoverText");
  6140     var yearDiff = this._band.getMinDate().getUTCFullYear() - this._startDate.getUTCFullYear();
  3593 this._title=D("caption");
  6141     minDate.setUTCFullYear(this._band.getMinDate().getUTCFullYear() - yearDiff % this._multiple);
  3594 this._icon=D("icon");
  6142 
  3595 this._color=D("color");
  6143     var p = this;
  3596 this._textColor=D("textColor");
  6144     var incrementDate = function(date) {
  3597 this._classname=D("classname");
  6145         for (var i = 0; i < p._multiple; i++) {
  3598 this._tapeImage=D("tapeImage");
  6146             SimileAjax.DateTime.incrementByInterval(date, SimileAjax.DateTime.YEAR);
  3599 this._tapeRepeat=D("tapeRepeat");
  6147         }
  3600 this._trackNum=D("trackNum");
  6148     };
  3601 if(this._trackNum!=null){this._trackNum=parseInt(this._trackNum);
  6149     var labeller = {
  3602 }this._wikiURL=null;
  6150         labelInterval: function(date, intervalUnit) {
  3603 this._wikiSection=null;
  6151             var diff = date.getUTCFullYear() - p._startDate.getUTCFullYear();
  3604 };
  6152             return {
  3605 Timeline.DefaultEventSource.Event.prototype={getID:function(){return this._id;
  6153                 text: diff,
  3606 },isInstant:function(){return this._instant;
  6154                 emphasized: diff == 0
  3607 },isImprecise:function(){return this._start!=this._latestStart||this._end!=this._earliestEnd;
  6155             };
  3608 },getStart:function(){return this._start;
  6156         }
  3609 },getEnd:function(){return this._end;
  6157     };
  3610 },getLatestStart:function(){return this._latestStart;
  6158 
  3611 },getEarliestEnd:function(){return this._earliestEnd;
  6159     while (minDate.getTime() < maxDate.getTime()) {
  3612 },getEventID:function(){return this._eventID;
  6160         this._intervalMarkerLayout.createIntervalMarker(
  3613 },getText:function(){return this._text;
  6161             minDate, labeller, SimileAjax.DateTime.YEAR, this._markerLayer, this._lineLayer);
  3614 },getDescription:function(){return this._description;
  6162 
  3615 },getImage:function(){return this._image;
  6163         incrementDate(minDate);
  3616 },getLink:function(){return this._link;
  6164     }
  3617 },getIcon:function(){return this._icon;
  6165     this._markerLayer.style.display = "block";
  3618 },getColor:function(){return this._color;
  6166     this._lineLayer.style.display = "block";
  3619 },getTextColor:function(){return this._textColor;
  6167 };
  3620 },getClassName:function(){return this._classname;
  6168 
  3621 },getTapeImage:function(){return this._tapeImage;
  6169 Timeline.YearCountEtherPainter.prototype.softPaint = function() {
  3622 },getTapeRepeat:function(){return this._tapeRepeat;
  6170 };
  3623 },getTrackNum:function(){return this._trackNum;
  6171 
  3624 },getProperty:function(A){return null;
  6172 /*==================================================
  3625 },getWikiURL:function(){return this._wikiURL;
  6173  *  Quarterly Ether Painter
  3626 },getWikiSection:function(){return this._wikiSection;
  6174  *==================================================
  3627 },setWikiInfo:function(B,A){this._wikiURL=B;
  6175  */
  3628 this._wikiSection=A;
  6176 
  3629 },fillDescription:function(A){A.innerHTML=this._description;
  6177 Timeline.QuarterlyEtherPainter = function(params) {
  3630 },fillWikiInfo:function(D){D.style.display="none";
  6178     this._params = params;
  3631 if(this._wikiURL==null||this._wikiSection==null){return ;
  6179     this._theme = params.theme;
  3632 }var C=this.getProperty("wikiID");
  6180     this._startDate = SimileAjax.DateTime.parseGregorianDateTime(params.startDate);
  3633 if(C==null||C.length==0){C=this.getText();
  6181 };
  3634 }if(C==null||C.length==0){return ;
  6182 
  3635 }D.style.display="inline";
  6183 Timeline.QuarterlyEtherPainter.prototype.initialize = function(band, timeline) {
  3636 C=C.replace(/\s/g,"_");
  6184     this._band = band;
  3637 var B=this._wikiURL+this._wikiSection.replace(/\s/g,"_")+"/"+C;
  6185     this._timeline = timeline;
  3638 var A=document.createElement("a");
  6186 
  3639 A.href=B;
  6187     this._backgroundLayer = band.createLayerDiv(0);
  3640 A.target="new";
  6188     this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
  3641 A.innerHTML=Timeline.strings[Timeline.clientLocale].wikiLinkLabel;
  6189     this._backgroundLayer.className = 'timeline-ether-bg';
  3642 D.appendChild(document.createTextNode("["));
  6190  //   this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
  3643 D.appendChild(A);
  6191 
  3644 D.appendChild(document.createTextNode("]"));
  6192     this._markerLayer = null;
  3645 },fillTime:function(A,B){if(this._instant){if(this.isImprecise()){A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._start)));
  6193     this._lineLayer = null;
  3646 A.appendChild(A.ownerDocument.createElement("br"));
  6194 
  3647 A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._end)));
  6195     var align = ("align" in this._params) ? this._params.align :
  3648 }else{A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._start)));
  6196         this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
  3649 }}else{if(this.isImprecise()){A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._start)+" ~ "+B.labelPrecise(this._latestStart)));
  6197     var showLine = ("showLine" in this._params) ? this._params.showLine :
  3650 A.appendChild(A.ownerDocument.createElement("br"));
  6198         this._theme.ether.interval.line.show;
  3651 A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._earliestEnd)+" ~ "+B.labelPrecise(this._end)));
  6199 
  3652 }else{A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._start)));
  6200     this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
  3653 A.appendChild(A.ownerDocument.createElement("br"));
  6201         this._timeline, this._band, this._theme, align, showLine);
  3654 A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._end)));
  6202 
  3655 }}},fillInfoBubble:function(A,D,K){var L=A.ownerDocument;
  6203     this._highlight = new Timeline.EtherHighlight(
  3656 var J=this.getText();
  6204         this._timeline, this._band, this._theme, this._backgroundLayer);
  3657 var H=this.getLink();
  6205 };
  3658 var C=this.getImage();
  6206 
  3659 if(C!=null){var E=L.createElement("img");
  6207 Timeline.QuarterlyEtherPainter.prototype.setHighlight = function(startDate, endDate) {
  3660 E.src=C;
  6208     this._highlight.position(startDate, endDate);
  3661 D.event.bubble.imageStyler(E);
  6209 };
  3662 A.appendChild(E);
  6210 
  3663 }var M=L.createElement("div");
  6211 Timeline.QuarterlyEtherPainter.prototype.paint = function() {
  3664 var B=L.createTextNode(J);
  6212     if (this._markerLayer) {
  3665 if(H!=null){var I=L.createElement("a");
  6213         this._band.removeLayerDiv(this._markerLayer);
  3666 I.href=H;
  6214     }
  3667 I.appendChild(B);
  6215     this._markerLayer = this._band.createLayerDiv(100);
  3668 M.appendChild(I);
  6216     this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
  3669 }else{M.appendChild(B);
  6217     this._markerLayer.style.display = "none";
  3670 }D.event.bubble.titleStyler(M);
  6218 
  3671 A.appendChild(M);
  6219     if (this._lineLayer) {
  3672 var N=L.createElement("div");
  6220         this._band.removeLayerDiv(this._lineLayer);
  3673 this.fillDescription(N);
  6221     }
  3674 D.event.bubble.bodyStyler(N);
  6222     this._lineLayer = this._band.createLayerDiv(1);
  3675 A.appendChild(N);
  6223     this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
  3676 var G=L.createElement("div");
  6224     this._lineLayer.style.display = "none";
  3677 this.fillTime(G,K);
  6225 
  3678 D.event.bubble.timeStyler(G);
  6226     var minDate = new Date(0);
  3679 A.appendChild(G);
  6227     var maxDate = this._band.getMaxDate();
  3680 var F=L.createElement("div");
  6228 
  3681 this.fillWikiInfo(F);
  6229     minDate.setUTCFullYear(Math.max(this._startDate.getUTCFullYear(), this._band.getMinDate().getUTCFullYear()));
  3682 D.event.bubble.wikiStyler(F);
  6230     minDate.setUTCMonth(this._startDate.getUTCMonth());
  3683 A.appendChild(F);
  6231 
  3684 }};
  6232     var p = this;
  3685 
  6233     var incrementDate = function(date) {
  3686 
  6234         date.setUTCMonth(date.getUTCMonth() + 3);
  3687 /* themes.js */
  6235     };
  3688 Timeline.ClassicTheme=new Object();
  6236     var labeller = {
  3689 Timeline.ClassicTheme.implementations=[];
  6237         labelInterval: function(date, intervalUnit) {
  3690 Timeline.ClassicTheme.create=function(A){if(A==null){A=Timeline.getDefaultLocale();
  6238             var quarters = (4 + (date.getUTCMonth() - p._startDate.getUTCMonth()) / 3) % 4;
  3691 }var B=Timeline.ClassicTheme.implementations[A];
  6239             if (quarters != 0) {
  3692 if(B==null){B=Timeline.ClassicTheme._Impl;
  6240                 return { text: "Q" + (quarters + 1), emphasized: false };
  3693 }return new B();
  6241             } else {
  3694 };
  6242                 return { text: "Y" + (date.getUTCFullYear() - p._startDate.getUTCFullYear() + 1), emphasized: true };
  3695 Timeline.ClassicTheme._Impl=function(){this.firstDayOfWeek=0;
  6243             }
  3696 this.autoWidth=false;
  6244         }
  3697 this.autoWidthAnimationTime=1000;
  6245     };
  3698 this.ether={backgroundColors:[],highlightOpacity:50,interval:{line:{show:true,opacity:25},weekend:{opacity:30},marker:{hAlign:"Bottom",vAlign:"Right"}}};
  6246 
  3699 this.event={track:{height:10,gap:2,offset:2,autoWidthMargin:1.5},overviewTrack:{offset:20,tickHeight:6,height:2,gap:1,autoWidthMargin:5},tape:{height:4},instant:{icon:Timeline.urlPrefix+"data/timeline/dull-blue-circle.png",iconWidth:10,iconHeight:10,impreciseOpacity:20,impreciseIconMargin:3},duration:{impreciseOpacity:20},label:{backgroundOpacity:50,offsetFromLine:3},highlightColors:["#FFFF00","#FFC000","#FF0000","#0000FF"],highlightLabelBackground:false,bubble:{width:250,maxHeight:0,titleStyler:function(A){A.className="timeline-event-bubble-title";
  6247     while (minDate.getTime() < maxDate.getTime()) {
  3700 },bodyStyler:function(A){A.className="timeline-event-bubble-body";
  6248         this._intervalMarkerLayout.createIntervalMarker(
  3701 },imageStyler:function(A){A.className="timeline-event-bubble-image";
  6249             minDate, labeller, SimileAjax.DateTime.YEAR, this._markerLayer, this._lineLayer);
  3702 },wikiStyler:function(A){A.className="timeline-event-bubble-wiki";
  6250 
  3703 },timeStyler:function(A){A.className="timeline-event-bubble-time";
  6251         incrementDate(minDate);
  3704 }}};
  6252     }
  3705 this.mouseWheel="scroll";
  6253     this._markerLayer.style.display = "block";
  3706 };
  6254     this._lineLayer.style.display = "block";
  3707 
  6255 };
  3708 
  6256 
  3709 /* timeline.js */
  6257 Timeline.QuarterlyEtherPainter.prototype.softPaint = function() {
  3710 Timeline.strings={};
  6258 };
  3711 Timeline.HORIZONTAL=0;
  6259 
  3712 Timeline.VERTICAL=1;
  6260 /*==================================================
  3713 Timeline._defaultTheme=null;
  6261  *  Ether Interval Marker Layout
  3714 Timeline.getDefaultLocale=function(){return Timeline.clientLocale;
  6262  *==================================================
  3715 };
  6263  */
  3716 Timeline.create=function(D,C,B,F){if(Timeline.timelines==null){Timeline.timelines=[];
  6264 
  3717 }var A=Timeline.timelines.length;
  6265 Timeline.EtherIntervalMarkerLayout = function(timeline, band, theme, align, showLine) {
  3718 Timeline.timelines[A]=null;
  6266     var horizontal = timeline.isHorizontal();
  3719 var E=new Timeline._Impl(D,C,B,F,A);
  6267     if (horizontal) {
  3720 Timeline.timelines[A]=E;
  6268         if (align == "Top") {
  3721 return E;
  6269             this.positionDiv = function(div, offset) {
  3722 };
  6270                 div.style.left = offset + "px";
  3723 Timeline.createBandInfo=function(D){var E=("theme" in D)?D.theme:Timeline.getDefaultTheme();
  6271                 div.style.top = "0px";
  3724 var B=("eventSource" in D)?D.eventSource:null;
  6272             };
  3725 var F={interval:SimileAjax.DateTime.gregorianUnitLengths[D.intervalUnit],pixelsPerInterval:D.intervalPixels,theme:E};
  6273         } else {
  3726 if("startsOn" in D||"endsOn" in D){if("startsOn" in D){F.startsOn=D.startsOn;
  6274             this.positionDiv = function(div, offset) {
  3727 }if("endsOn" in D){F.endsOn=D.endsOn;
  6275                 div.style.left = offset + "px";
  3728 }}else{F.centersOn=("date" in D)?D.date:new Date();
  6276                 div.style.bottom = "0px";
  3729 }var G=new Timeline.LinearEther(F);
  6277             };
  3730 var H=new Timeline.GregorianEtherPainter({unit:D.intervalUnit,multiple:("multiple" in D)?D.multiple:1,theme:E,align:("align" in D)?D.align:undefined});
  6278         }
  3731 var J={showText:("showEventText" in D)?D.showEventText:true,theme:E};
  6279     } else {
  3732 if("eventPainterParams" in D){for(var A in D.eventPainterParams){J[A]=D.eventPainterParams[A];
  6280         if (align == "Left") {
  3733 }}if("trackHeight" in D){J.trackHeight=D.trackHeight;
  6281             this.positionDiv = function(div, offset) {
  3734 }if("trackGap" in D){J.trackGap=D.trackGap;
  6282                 div.style.top = offset + "px";
  3735 }var I=("overview" in D&&D.overview)?"overview":("layout" in D?D.layout:"original");
  6283                 div.style.left = "0px";
  3736 var C;
  6284             };
  3737 if("eventPainter" in D){C=new D.eventPainter(J);
  6285         } else {
  3738 }else{switch(I){case"overview":C=new Timeline.OverviewEventPainter(J);
  6286             this.positionDiv = function(div, offset) {
  3739 break;
  6287                 div.style.top = offset + "px";
  3740 case"detailed":C=new Timeline.DetailedEventPainter(J);
  6288                 div.style.right = "0px";
  3741 break;
  6289             };
  3742 default:C=new Timeline.OriginalEventPainter(J);
  6290         }
  3743 }}return{width:D.width,eventSource:B,timeZone:("timeZone" in D)?D.timeZone:0,ether:G,etherPainter:H,eventPainter:C,theme:E,zoomIndex:("zoomIndex" in D)?D.zoomIndex:0,zoomSteps:("zoomSteps" in D)?D.zoomSteps:null};
  6291     }
  3744 };
  6292 
  3745 Timeline.createHotZoneBandInfo=function(D){var E=("theme" in D)?D.theme:Timeline.getDefaultTheme();
  6293     var markerTheme = theme.ether.interval.marker;
  3746 var B=("eventSource" in D)?D.eventSource:null;
  6294     var lineTheme = theme.ether.interval.line;
  3747 var F=new Timeline.HotZoneEther({centersOn:("date" in D)?D.date:new Date(),interval:SimileAjax.DateTime.gregorianUnitLengths[D.intervalUnit],pixelsPerInterval:D.intervalPixels,zones:D.zones,theme:E});
  6295     var weekendTheme = theme.ether.interval.weekend;
  3748 var G=new Timeline.HotZoneGregorianEtherPainter({unit:D.intervalUnit,zones:D.zones,theme:E,align:("align" in D)?D.align:undefined});
  6296 
  3749 var I={showText:("showEventText" in D)?D.showEventText:true,theme:E};
  6297     var stylePrefix = (horizontal ? "h" : "v") + align;
  3750 if("eventPainterParams" in D){for(var A in D.eventPainterParams){I[A]=D.eventPainterParams[A];
  6298     var labelStyler = markerTheme[stylePrefix + "Styler"];
  3751 }}if("trackHeight" in D){I.trackHeight=D.trackHeight;
  6299     var emphasizedLabelStyler = markerTheme[stylePrefix + "EmphasizedStyler"];
  3752 }if("trackGap" in D){I.trackGap=D.trackGap;
  6300     var day = SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.DAY];
  3753 }var H=("overview" in D&&D.overview)?"overview":("layout" in D?D.layout:"original");
  6301 
  3754 var C;
  6302     this.createIntervalMarker = function(date, labeller, unit, markerDiv, lineDiv) {
  3755 if("eventPainter" in D){C=new D.eventPainter(I);
  6303         var offset = Math.round(band.dateToPixelOffset(date));
  3756 }else{switch(H){case"overview":C=new Timeline.OverviewEventPainter(I);
  6304 
  3757 break;
  6305         if (showLine && unit != SimileAjax.DateTime.WEEK) {
  3758 case"detailed":C=new Timeline.DetailedEventPainter(I);
  6306             var divLine = timeline.getDocument().createElement("div");
  3759 break;
  6307             divLine.className = "timeline-ether-lines";
  3760 default:C=new Timeline.OriginalEventPainter(I);
  6308 
  3761 }}return{width:D.width,eventSource:B,timeZone:("timeZone" in D)?D.timeZone:0,ether:F,etherPainter:G,eventPainter:C,theme:E,zoomIndex:("zoomIndex" in D)?D.zoomIndex:0,zoomSteps:("zoomSteps" in D)?D.zoomSteps:null};
  6309             if (lineTheme.opacity < 100) {
  3762 };
  6310                 SimileAjax.Graphics.setOpacity(divLine, lineTheme.opacity);
  3763 Timeline.getDefaultTheme=function(){if(Timeline._defaultTheme==null){Timeline._defaultTheme=Timeline.ClassicTheme.create(Timeline.getDefaultLocale());
  6311             }
  3764 }return Timeline._defaultTheme;
  6312 
  3765 };
  6313             if (horizontal) {
  3766 Timeline.setDefaultTheme=function(A){Timeline._defaultTheme=A;
  6314 				//divLine.className += " timeline-ether-lines-vertical";
  3767 };
  6315 				divLine.style.left = offset + "px";
  3768 Timeline.loadXML=function(A,C){var D=function(G,E,F){alert("Failed to load data xml from "+A+"\n"+G);
  6316             } else {
  3769 };
  6317 				//divLine.className += " timeline-ether-lines-horizontal";
  3770 var B=function(F){var E=F.responseXML;
  6318                 divLine.style.top = offset + "px";
  3771 if(!E.documentElement&&F.responseStream){E.load(F.responseStream);
  6319             }
  3772 }C(E,A);
  6320             lineDiv.appendChild(divLine);
  3773 };
  6321         }
  3774 SimileAjax.XmlHttp.get(A,D,B);
  6322         if (unit == SimileAjax.DateTime.WEEK) {
  3775 };
  6323             var firstDayOfWeek = theme.firstDayOfWeek;
  3776 Timeline.loadJSON=function(url,f){var fError=function(statusText,status,xmlhttp){alert("Failed to load json data from "+url+"\n"+statusText);
  6324 
  3777 };
  6325             var saturday = new Date(date.getTime() + (6 - firstDayOfWeek - 7) * day);
  3778 var fDone=function(xmlhttp){f(eval("("+xmlhttp.responseText+")"),url);
  6326             var monday = new Date(saturday.getTime() + 2 * day);
  3779 };
  6327 
  3780 SimileAjax.XmlHttp.get(url,fError,fDone);
  6328             var saturdayPixel = Math.round(band.dateToPixelOffset(saturday));
  3781 };
  6329             var mondayPixel = Math.round(band.dateToPixelOffset(monday));
  3782 Timeline.getTimelineFromID=function(A){return Timeline.timelines[A];
  6330             var length = Math.max(1, mondayPixel - saturdayPixel);
  3783 };
  6331 
  3784 Timeline._Impl=function(D,C,B,E,A){SimileAjax.WindowManager.initialize();
  6332             var divWeekend = timeline.getDocument().createElement("div");
  3785 this._containerDiv=D;
  6333 			divWeekend.className = 'timeline-ether-weekends'
  3786 this._bandInfos=C;
  6334 
  3787 this._orientation=B==null?Timeline.HORIZONTAL:B;
  6335             if (weekendTheme.opacity < 100) {
  3788 this._unit=(E!=null)?E:SimileAjax.NativeDateUnit;
  6336                 SimileAjax.Graphics.setOpacity(divWeekend, weekendTheme.opacity);
  3789 this._starting=true;
  6337             }
  3790 this._autoResizing=false;
  6338 
  3791 this.autoWidth=C&&C[0]&&C[0].theme&&C[0].theme.autoWidth;
  6339             if (horizontal) {
  3792 this.autoWidthAnimationTime=C&&C[0]&&C[0].theme&&C[0].theme.autoWidthAnimationTime;
  6340                 divWeekend.style.left = saturdayPixel + "px";
  3793 this.timelineID=A;
  6341                 divWeekend.style.width = length + "px";
  3794 this._initialize();
  6342             } else {
  3795 };
  6343                 divWeekend.style.top = saturdayPixel + "px";
  3796 Timeline._Impl.prototype.dispose=function(){for(var A=0;
  6344                 divWeekend.style.height = length + "px";
  3797 A<this._bands.length;
  6345             }
  3798 A++){this._bands[A].dispose();
  6346             lineDiv.appendChild(divWeekend);
  3799 }this._bands=null;
  6347         }
  3800 this._bandInfos=null;
  6348 
  3801 this._containerDiv.innerHTML="";
  6349         var label = labeller.labelInterval(date, unit);
  3802 Timeline.timelines[this.timelineID]=null;
  6350 
  3803 };
  6351         var div = timeline.getDocument().createElement("div");
  3804 Timeline._Impl.prototype.getBandCount=function(){return this._bands.length;
  6352         div.innerHTML = label.text;
  3805 };
  6353 
  3806 Timeline._Impl.prototype.getBand=function(A){return this._bands[A];
  6354 
  3807 };
  6355 
  3808 Timeline._Impl.prototype.finishedEventLoading=function(){this._autoWidthCheck(true);
  6356 		div.className = 'timeline-date-label'
  3809 this._starting=false;
  6357 		if(label.emphasized) div.className += ' timeline-date-label-em'
  3810 };
  6358 
  3811 Timeline._Impl.prototype.layout=function(){this._autoWidthCheck(true);
  6359         this.positionDiv(div, offset);
  3812 this._distributeWidths();
  6360         markerDiv.appendChild(div);
  3813 };
  6361 
  3814 Timeline._Impl.prototype.paint=function(){for(var A=0;
  6362         return div;
  3815 A<this._bands.length;
  6363     };
  3816 A++){this._bands[A].paint();
  6364 };
  3817 }};
  6365 
  3818 Timeline._Impl.prototype.getDocument=function(){return this._containerDiv.ownerDocument;
  6366 /*==================================================
  3819 };
  6367  *  Ether Highlight Layout
  3820 Timeline._Impl.prototype.addDiv=function(A){this._containerDiv.appendChild(A);
  6368  *==================================================
  3821 };
  6369  */
  3822 Timeline._Impl.prototype.removeDiv=function(A){this._containerDiv.removeChild(A);
  6370 
  3823 };
  6371 Timeline.EtherHighlight = function(timeline, band, theme, backgroundLayer) {
  3824 Timeline._Impl.prototype.isHorizontal=function(){return this._orientation==Timeline.HORIZONTAL;
  6372     var horizontal = timeline.isHorizontal();
  3825 };
  6373 
  3826 Timeline._Impl.prototype.isVertical=function(){return this._orientation==Timeline.VERTICAL;
  6374     this._highlightDiv = null;
  3827 };
  6375     this._createHighlightDiv = function() {
  3828 Timeline._Impl.prototype.getPixelLength=function(){return this._orientation==Timeline.HORIZONTAL?this._containerDiv.offsetWidth:this._containerDiv.offsetHeight;
  6376         if (this._highlightDiv == null) {
  3829 };
  6377             this._highlightDiv = timeline.getDocument().createElement("div");
  3830 Timeline._Impl.prototype.getPixelWidth=function(){return this._orientation==Timeline.VERTICAL?this._containerDiv.offsetWidth:this._containerDiv.offsetHeight;
  6378             this._highlightDiv.setAttribute("name", "ether-highlight"); // for debugging
  3831 };
  6379             this._highlightDiv.className = 'timeline-ether-highlight'
  3832 Timeline._Impl.prototype.getUnit=function(){return this._unit;
  6380 
  3833 };
  6381             var opacity = theme.ether.highlightOpacity;
  3834 Timeline._Impl.prototype.getWidthStyle=function(){return this._orientation==Timeline.HORIZONTAL?"height":"width";
  6382             if (opacity < 100) {
  3835 };
  6383                 SimileAjax.Graphics.setOpacity(this._highlightDiv, opacity);
  3836 Timeline._Impl.prototype.loadXML=function(B,D){var A=this;
  6384             }
  3837 var E=function(H,F,G){alert("Failed to load data xml from "+B+"\n"+H);
  6385 
  3838 A.hideLoadingMessage();
  6386             backgroundLayer.appendChild(this._highlightDiv);
  3839 };
  6387         }
  3840 var C=function(G){try{var F=G.responseXML;
  6388     }
  3841 if(!F.documentElement&&G.responseStream){F.load(G.responseStream);
  6389 
  3842 }D(F,B);
  6390     this.position = function(startDate, endDate) {
  3843 }finally{A.hideLoadingMessage();
  6391         this._createHighlightDiv();
  3844 }};
  6392 
  3845 this.showLoadingMessage();
  6393         var startPixel = Math.round(band.dateToPixelOffset(startDate));
  3846 window.setTimeout(function(){SimileAjax.XmlHttp.get(B,E,C);
  6394         var endPixel = Math.round(band.dateToPixelOffset(endDate));
  3847 },0);
  6395         var length = Math.max(endPixel - startPixel, 3);
  3848 };
  6396         if (horizontal) {
  3849 Timeline._Impl.prototype.loadJSON=function(url,f){var tl=this;
  6397             this._highlightDiv.style.left = startPixel + "px";
  3850 var fError=function(statusText,status,xmlhttp){alert("Failed to load json data from "+url+"\n"+statusText);
  6398             this._highlightDiv.style.width = length + "px";
  3851 tl.hideLoadingMessage();
  6399             this._highlightDiv.style.height = (band.getViewWidth() - 4) + "px";
  3852 };
  6400         } else {
  3853 var fDone=function(xmlhttp){try{f(eval("("+xmlhttp.responseText+")"),url);
  6401             this._highlightDiv.style.top = startPixel + "px";
  3854 }finally{tl.hideLoadingMessage();
  6402             this._highlightDiv.style.height = length + "px";
  3855 }};
  6403             this._highlightDiv.style.width = (band.getViewWidth() - 4) + "px";
  3856 this.showLoadingMessage();
  6404         }
  3857 window.setTimeout(function(){SimileAjax.XmlHttp.get(url,fError,fDone);
  6405     }
  3858 },0);
  6406 };
  3859 };
  6407 /*==================================================
  3860 Timeline._Impl.prototype._autoWidthScrollListener=function(A){A.getTimeline()._autoWidthCheck(false);
  6408  *  Event Utils
  3861 };
  6409  *==================================================
  3862 Timeline._Impl.prototype._autoWidthCheck=function(C){var E=this;
  6410  */
  3863 var B=E._starting;
  6411 Timeline.EventUtils = {};
  3864 var D=0;
  6412 
  3865 function A(){var H=E.getWidthStyle();
  6413 Timeline.EventUtils.getNewEventID = function() {
  3866 if(B){E._containerDiv.style[H]=D+"px";
  6414     // global across page
  3867 }else{E._autoResizing=true;
  6415     if (this._lastEventID == null) {
  3868 var G={};
  6416         this._lastEventID = 0;
  3869 G[H]=D+"px";
  6417     }
  3870 SimileAjax.jQuery(E._containerDiv).animate(G,E.autoWidthAnimationTime,"linear",function(){E._autoResizing=false;
  6418 
  3871 });
  6419     this._lastEventID += 1;
  3872 }}function F(){var I=0;
  6420     return "e" + this._lastEventID;
  3873 var G=E.getPixelWidth();
  6421 };
  3874 if(E._autoResizing){return ;
  6422 
  3875 }for(var H=0;
  6423 Timeline.EventUtils.decodeEventElID = function(elementID) {
  3876 H<E._bands.length;
  6424     /*==================================================
  3877 H++){E._bands[H].checkAutoWidth();
  6425      *
  3878 I+=E._bandInfos[H].width;
  6426      * Use this function to decode an event element's id on a band (label div,
  3879 }if(I>G||C){D=I;
  6427      * tape div or icon img).
  3880 A();
  6428      *
  3881 E._distributeWidths();
  6429      * Returns {band: <bandObj>, evt: <eventObj>}
  3882 }}if(!E.autoWidth){return ;
  6430      *
  3883 }F();
  6431      * To enable a single event listener to monitor everything
  3884 };
  6432      * on a Timeline, a set format is used for the id's of the
  3885 Timeline._Impl.prototype._initialize=function(){var E=this._containerDiv;
  6433      * elements on the Timeline--
  3886 var G=E.ownerDocument;
  6434      *
  3887 E.className=E.className.split(" ").concat("timeline-container").join(" ");
  6435      * element id format for labels, icons, tapes:
  3888 var A=(this.isHorizontal())?"horizontal":"vertical";
  6436      *   labels: label-tl-<timelineID>-<band_index>-<evt.id>
  3889 E.className+=" timeline-"+A;
  6437      *    icons: icon-tl-<timelineID>-<band_index>-<evt.id>
  3890 while(E.firstChild){E.removeChild(E.firstChild);
  6438      *    tapes: tape1-tl-<timelineID>-<band_index>-<evt.id>
  3891 }var B=SimileAjax.Graphics.createTranslucentImage(Timeline.urlPrefix+(this.isHorizontal()?"data/timeline/copyright-vertical.png":"data/timeline/copyright.png"));
  6439      *           tape2-tl-<timelineID>-<band_index>-<evt.id>
  3892 B.className="timeline-copyright";
  6440      *           // some events have more than one tape
  3893 B.title="Timeline &copy; SIMILE - http://simile.mit.edu/timeline/";
  6441      *    highlight: highlight1-tl-<timelineID>-<band_index>-<evt.id>
  3894 SimileAjax.DOM.registerEvent(B,"click",function(){window.location="http://simile.mit.edu/timeline/";
  6442      *               highlight2-tl-<timelineID>-<band_index>-<evt.id>
  3895 });
  6443      *           // some events have more than one highlight div (future)
  3896 E.appendChild(B);
  6444      * Note: use split('-') to get array of the format's parts
  3897 this._bands=[];
  6445      *
  3898 for(var C=0;
  6446      * You can then retrieve the timeline object and event object
  3899 C<this._bandInfos.length;
  6447      * by using Timeline.getTimeline, Timeline.getBand, or
  3900 C++){var F=this._bandInfos[C];
  6448      * Timeline.getEvent and passing in the element's id
  3901 var D=F.bandClass||Timeline._Band;
  6449      *
  3902 var H=new D(this,this._bandInfos[C],C);
  6450      *==================================================
  3903 this._bands.push(H);
  6451      */
  3904 }this._distributeWidths();
  6452 
  3905 for(var C=0;
  6453     var parts = elementID.split('-');
  3906 C<this._bandInfos.length;
  6454     if (parts[1] != 'tl') {
  3907 C++){var F=this._bandInfos[C];
  6455         alert("Internal Timeline problem 101, please consult support");
  3908 if("syncWith" in F){this._bands[C].setSyncWithBand(this._bands[F.syncWith],("highlight" in F)?F.highlight:false);
  6456         return {band: null, evt: null}; // early return
  3909 }}if(this.autoWidth){for(var C=0;
  6457     }
  3910 C<this._bands.length;
  6458 
  3911 C++){this._bands[C].addOnScrollListener(this._autoWidthScrollListener);
  6459     var timeline = Timeline.getTimelineFromID(parts[2]);
  3912 }}var I=SimileAjax.Graphics.createMessageBubble(G);
  6460     var band = timeline.getBand(parts[3]);
  3913 I.containerDiv.className="timeline-message-container";
  6461     var evt = band.getEventSource.getEvent(parts[4]);
  3914 E.appendChild(I.containerDiv);
  6462 
  3915 I.contentDiv.className="timeline-message";
  6463     return {band: band, evt: evt};
  3916 I.contentDiv.innerHTML="<img src='"+Timeline.urlPrefix+"data/timeline/progress-running.gif' /> Loading...";
  6464 };
  3917 this.showLoadingMessage=function(){I.containerDiv.style.display="block";
  6465 
  3918 };
  6466 Timeline.EventUtils.encodeEventElID = function(timeline, band, elType, evt) {
  3919 this.hideLoadingMessage=function(){I.containerDiv.style.display="none";
  6467     // elType should be one of {label | icon | tapeN | highlightN}
  3920 };
  6468     return elType + "-tl-" + timeline.timelineID +
  3921 };
  6469        "-" + band.getIndex() + "-" + evt.getID();
  3922 Timeline._Impl.prototype._distributeWidths=function(){var B=this.getPixelLength();
  6470 };/*==================================================
  3923 var A=this.getPixelWidth();
  6471  *  Gregorian Date Labeller
  3924 var C=0;
  6472  *==================================================
  3925 for(var E=0;
  6473  */
  3926 E<this._bands.length;
  6474 
  3927 E++){var I=this._bands[E];
  6475 Timeline.GregorianDateLabeller = function(locale, timeZone) {
  3928 var J=this._bandInfos[E];
  6476     this._locale = locale;
  3929 var F=J.width;
  6477     this._timeZone = timeZone;
  3930 var D;
  6478 };
  3931 if(typeof F=="string"){var H=F.indexOf("%");
  6479 
  3932 if(H>0){var G=parseInt(F.substr(0,H));
  6480 Timeline.GregorianDateLabeller.monthNames = [];
  3933 D=Math.round(G*A/100);
  6481 Timeline.GregorianDateLabeller.dayNames = [];
  3934 }else{D=parseInt(F);
  6482 Timeline.GregorianDateLabeller.labelIntervalFunctions = [];
  3935 }}else{D=F;
  6483 
  3936 }I.setBandShiftAndWidth(C,D);
  6484 Timeline.GregorianDateLabeller.getMonthName = function(month, locale) {
  3937 I.setViewLength(B);
  6485     return Timeline.GregorianDateLabeller.monthNames[locale][month];
  3938 C+=D;
  6486 };
  3939 }};
  6487 
  3940 Timeline._Impl.prototype.zoom=function(G,B,F,D){var C=new RegExp("^timeline-band-([0-9]+)$");
  6488 Timeline.GregorianDateLabeller.prototype.labelInterval = function(date, intervalUnit) {
  3941 var E=null;
  6489     var f = Timeline.GregorianDateLabeller.labelIntervalFunctions[this._locale];
  3942 var A=C.exec(D.id);
  6490     if (f == null) {
  3943 if(A){E=parseInt(A[1]);
  6491         f = Timeline.GregorianDateLabeller.prototype.defaultLabelInterval;
  3944 }if(E!=null){this._bands[E].zoom(G,B,F,D);
  6492     }
  3945 }this.paint();
  6493     return f.call(this, date, intervalUnit);
  3946 };
  6494 };
  3947 
  6495 
  3948 
  6496 Timeline.GregorianDateLabeller.prototype.labelPrecise = function(date) {
  3949 /* units.js */
  6497     return SimileAjax.DateTime.removeTimeZoneOffset(
  3950 Timeline.NativeDateUnit=new Object();
  6498         date,
  3951 Timeline.NativeDateUnit.createLabeller=function(A,B){return new Timeline.GregorianDateLabeller(A,B);
  6499         this._timeZone //+ (new Date().getTimezoneOffset() / 60)
  3952 };
  6500     ).toUTCString();
  3953 Timeline.NativeDateUnit.makeDefaultValue=function(){return new Date();
  6501 };
  3954 };
  6502 
  3955 Timeline.NativeDateUnit.cloneValue=function(A){return new Date(A.getTime());
  6503 Timeline.GregorianDateLabeller.prototype.defaultLabelInterval = function(date, intervalUnit) {
  3956 };
  6504     var text;
  3957 Timeline.NativeDateUnit.getParser=function(A){if(typeof A=="string"){A=A.toLowerCase();
  6505     var emphasized = false;
  3958 }return(A=="iso8601"||A=="iso 8601")?Timeline.DateTime.parseIso8601DateTime:Timeline.DateTime.parseGregorianDateTime;
  6506 
  3959 };
  6507     date = SimileAjax.DateTime.removeTimeZoneOffset(date, this._timeZone);
  3960 Timeline.NativeDateUnit.parseFromObject=function(A){return Timeline.DateTime.parseGregorianDateTime(A);
  6508 
  3961 };
  6509     switch(intervalUnit) {
  3962 Timeline.NativeDateUnit.toNumber=function(A){return A.getTime();
  6510     case SimileAjax.DateTime.MILLISECOND:
  3963 };
  6511         text = date.getUTCMilliseconds();
  3964 Timeline.NativeDateUnit.fromNumber=function(A){return new Date(A);
  6512         break;
  3965 };
  6513     case SimileAjax.DateTime.SECOND:
  3966 Timeline.NativeDateUnit.compare=function(D,C){var B,A;
  6514         text = date.getUTCSeconds();
  3967 if(typeof D=="object"){B=D.getTime();
  6515         break;
  3968 }else{B=Number(D);
  6516     case SimileAjax.DateTime.MINUTE:
  3969 }if(typeof C=="object"){A=C.getTime();
  6517         var m = date.getUTCMinutes();
  3970 }else{A=Number(C);
  6518         if (m == 0) {
  3971 }return B-A;
  6519             text = date.getUTCHours() + ":00";
  3972 };
  6520             emphasized = true;
  3973 Timeline.NativeDateUnit.earlier=function(B,A){return Timeline.NativeDateUnit.compare(B,A)<0?B:A;
  6521         } else {
  3974 };
  6522             text = m;
  3975 Timeline.NativeDateUnit.later=function(B,A){return Timeline.NativeDateUnit.compare(B,A)>0?B:A;
  6523         }
  3976 };
  6524         break;
  3977 Timeline.NativeDateUnit.change=function(A,B){return new Date(A.getTime()+B);
  6525     case SimileAjax.DateTime.HOUR:
  3978 };
  6526         text = date.getUTCHours() + "hr";
  3979 
  6527         break;
  3980 /******** end of simile-timeline-bundle.js ********/
  6528     case SimileAjax.DateTime.DAY:
       
  6529         text = Timeline.GregorianDateLabeller.getMonthName(date.getUTCMonth(), this._locale) + " " + date.getUTCDate();
       
  6530         break;
       
  6531     case SimileAjax.DateTime.WEEK:
       
  6532         text = Timeline.GregorianDateLabeller.getMonthName(date.getUTCMonth(), this._locale) + " " + date.getUTCDate();
       
  6533         break;
       
  6534     case SimileAjax.DateTime.MONTH:
       
  6535         var m = date.getUTCMonth();
       
  6536         if (m != 0) {
       
  6537             text = Timeline.GregorianDateLabeller.getMonthName(m, this._locale);
       
  6538             break;
       
  6539         } // else, fall through
       
  6540     case SimileAjax.DateTime.YEAR:
       
  6541     case SimileAjax.DateTime.DECADE:
       
  6542     case SimileAjax.DateTime.CENTURY:
       
  6543     case SimileAjax.DateTime.MILLENNIUM:
       
  6544         var y = date.getUTCFullYear();
       
  6545         if (y > 0) {
       
  6546             text = date.getUTCFullYear();
       
  6547         } else {
       
  6548             text = (1 - y) + "BC";
       
  6549         }
       
  6550         emphasized =
       
  6551             (intervalUnit == SimileAjax.DateTime.MONTH) ||
       
  6552             (intervalUnit == SimileAjax.DateTime.DECADE && y % 100 == 0) ||
       
  6553             (intervalUnit == SimileAjax.DateTime.CENTURY && y % 1000 == 0);
       
  6554         break;
       
  6555     default:
       
  6556         text = date.toUTCString();
       
  6557     }
       
  6558     return { text: text, emphasized: emphasized };
       
  6559 }
       
  6560 
       
  6561 /*==================================================
       
  6562  *  Default Event Source
       
  6563  *==================================================
       
  6564  */
       
  6565 
       
  6566 
       
  6567 Timeline.DefaultEventSource = function(eventIndex) {
       
  6568     this._events = (eventIndex instanceof Object) ? eventIndex : new SimileAjax.EventIndex();
       
  6569     this._listeners = [];
       
  6570 };
       
  6571 
       
  6572 Timeline.DefaultEventSource.prototype.addListener = function(listener) {
       
  6573     this._listeners.push(listener);
       
  6574 };
       
  6575 
       
  6576 Timeline.DefaultEventSource.prototype.removeListener = function(listener) {
       
  6577     for (var i = 0; i < this._listeners.length; i++) {
       
  6578         if (this._listeners[i] == listener) {
       
  6579             this._listeners.splice(i, 1);
       
  6580             break;
       
  6581         }
       
  6582     }
       
  6583 };
       
  6584 
       
  6585 Timeline.DefaultEventSource.prototype.loadXML = function(xml, url) {
       
  6586     var base = this._getBaseURL(url);
       
  6587 
       
  6588     var wikiURL = xml.documentElement.getAttribute("wiki-url");
       
  6589     var wikiSection = xml.documentElement.getAttribute("wiki-section");
       
  6590 
       
  6591     var dateTimeFormat = xml.documentElement.getAttribute("date-time-format");
       
  6592     var parseDateTimeFunction = this._events.getUnit().getParser(dateTimeFormat);
       
  6593 
       
  6594     var node = xml.documentElement.firstChild;
       
  6595     var added = false;
       
  6596     while (node != null) {
       
  6597         if (node.nodeType == 1) {
       
  6598             var description = "";
       
  6599             if (node.firstChild != null && node.firstChild.nodeType == 3) {
       
  6600                 description = node.firstChild.nodeValue;
       
  6601             }
       
  6602             // instant event: default is true. Or use values from isDuration or durationEvent
       
  6603             var instant = (node.getAttribute("isDuration")    === null &&
       
  6604                            node.getAttribute("durationEvent") === null) ||
       
  6605                           node.getAttribute("isDuration") == "false" ||
       
  6606                           node.getAttribute("durationEvent") == "false";
       
  6607 
       
  6608             var evt = new Timeline.DefaultEventSource.Event( {
       
  6609                           id: node.getAttribute("id"),
       
  6610                        start: parseDateTimeFunction(node.getAttribute("start")),
       
  6611                          end: parseDateTimeFunction(node.getAttribute("end")),
       
  6612                  latestStart: parseDateTimeFunction(node.getAttribute("latestStart")),
       
  6613                  earliestEnd: parseDateTimeFunction(node.getAttribute("earliestEnd")),
       
  6614                      instant: instant,
       
  6615                         text: node.getAttribute("title"),
       
  6616                  description: description,
       
  6617                        image: this._resolveRelativeURL(node.getAttribute("image"), base),
       
  6618                         link: this._resolveRelativeURL(node.getAttribute("link") , base),
       
  6619                         icon: this._resolveRelativeURL(node.getAttribute("icon") , base),
       
  6620                        color: node.getAttribute("color"),
       
  6621                    textColor: node.getAttribute("textColor"),
       
  6622                    hoverText: node.getAttribute("hoverText"),
       
  6623                    classname: node.getAttribute("classname"),
       
  6624                    tapeImage: node.getAttribute("tapeImage"),
       
  6625                   tapeRepeat: node.getAttribute("tapeRepeat"),
       
  6626                      caption: node.getAttribute("caption"),
       
  6627                      eventID: node.getAttribute("eventID"),
       
  6628                     trackNum: node.getAttribute("trackNum")
       
  6629             });
       
  6630 
       
  6631             evt._node = node;
       
  6632             evt.getProperty = function(name) {
       
  6633                 return this._node.getAttribute(name);
       
  6634             };
       
  6635             evt.setWikiInfo(wikiURL, wikiSection);
       
  6636 
       
  6637             this._events.add(evt);
       
  6638 
       
  6639             added = true;
       
  6640         }
       
  6641         node = node.nextSibling;
       
  6642     }
       
  6643 
       
  6644     if (added) {
       
  6645         this._fire("onAddMany", []);
       
  6646     }
       
  6647 };
       
  6648 
       
  6649 
       
  6650 Timeline.DefaultEventSource.prototype.loadJSON = function(data, url) {
       
  6651     var base = this._getBaseURL(url);
       
  6652     var added = false;
       
  6653     if (data && data.events){
       
  6654         var wikiURL = ("wikiURL" in data) ? data.wikiURL : null;
       
  6655         var wikiSection = ("wikiSection" in data) ? data.wikiSection : null;
       
  6656 
       
  6657         var dateTimeFormat = ("dateTimeFormat" in data) ? data.dateTimeFormat : null;
       
  6658         var parseDateTimeFunction = this._events.getUnit().getParser(dateTimeFormat);
       
  6659 
       
  6660         for (var i=0; i < data.events.length; i++){
       
  6661             var event = data.events[i];
       
  6662             // Fixing issue 33:
       
  6663             // instant event: default (for JSON only) is false. Or use values from isDuration or durationEvent
       
  6664             // isDuration was negated (see issue 33, so keep that interpretation
       
  6665             var instant = event.isDuration || (event.durationEvent != null && !event.durationEvent);
       
  6666 
       
  6667             var evt = new Timeline.DefaultEventSource.Event({
       
  6668                           id: ("id" in event) ? event.id : undefined,
       
  6669                        start: parseDateTimeFunction(event.start),
       
  6670                          end: parseDateTimeFunction(event.end),
       
  6671                  latestStart: parseDateTimeFunction(event.latestStart),
       
  6672                  earliestEnd: parseDateTimeFunction(event.earliestEnd),
       
  6673                      instant: instant,
       
  6674                         text: event.title,
       
  6675                  description: event.description,
       
  6676                        image: this._resolveRelativeURL(event.image, base),
       
  6677                         link: this._resolveRelativeURL(event.link , base),
       
  6678                         icon: this._resolveRelativeURL(event.icon , base),
       
  6679                        color: event.color,
       
  6680                    textColor: event.textColor,
       
  6681                    hoverText: event.hoverText,
       
  6682                    classname: event.classname,
       
  6683                    tapeImage: event.tapeImage,
       
  6684                   tapeRepeat: event.tapeRepeat,
       
  6685                      caption: event.caption,
       
  6686                      eventID: event.eventID,
       
  6687                     trackNum: event.trackNum
       
  6688             });
       
  6689             evt._obj = event;
       
  6690             evt.getProperty = function(name) {
       
  6691                 return this._obj[name];
       
  6692             };
       
  6693             evt.setWikiInfo(wikiURL, wikiSection);
       
  6694 
       
  6695             this._events.add(evt);
       
  6696             added = true;
       
  6697         }
       
  6698     }
       
  6699 
       
  6700     if (added) {
       
  6701         this._fire("onAddMany", []);
       
  6702     }
       
  6703 };
       
  6704 
       
  6705 /*
       
  6706  *  Contributed by Morten Frederiksen, http://www.wasab.dk/morten/
       
  6707  */
       
  6708 Timeline.DefaultEventSource.prototype.loadSPARQL = function(xml, url) {
       
  6709     var base = this._getBaseURL(url);
       
  6710 
       
  6711     var dateTimeFormat = 'iso8601';
       
  6712     var parseDateTimeFunction = this._events.getUnit().getParser(dateTimeFormat);
       
  6713 
       
  6714     if (xml == null) {
       
  6715         return;
       
  6716     }
       
  6717 
       
  6718     /*
       
  6719      *  Find <results> tag
       
  6720      */
       
  6721     var node = xml.documentElement.firstChild;
       
  6722     while (node != null && (node.nodeType != 1 || node.nodeName != 'results')) {
       
  6723         node = node.nextSibling;
       
  6724     }
       
  6725 
       
  6726     var wikiURL = null;
       
  6727     var wikiSection = null;
       
  6728     if (node != null) {
       
  6729         wikiURL = node.getAttribute("wiki-url");
       
  6730         wikiSection = node.getAttribute("wiki-section");
       
  6731 
       
  6732         node = node.firstChild;
       
  6733     }
       
  6734 
       
  6735     var added = false;
       
  6736     while (node != null) {
       
  6737         if (node.nodeType == 1) {
       
  6738             var bindings = { };
       
  6739             var binding = node.firstChild;
       
  6740             while (binding != null) {
       
  6741                 if (binding.nodeType == 1 &&
       
  6742                     binding.firstChild != null &&
       
  6743                     binding.firstChild.nodeType == 1 &&
       
  6744                     binding.firstChild.firstChild != null &&
       
  6745                     binding.firstChild.firstChild.nodeType == 3) {
       
  6746                     bindings[binding.getAttribute('name')] = binding.firstChild.firstChild.nodeValue;
       
  6747                 }
       
  6748                 binding = binding.nextSibling;
       
  6749             }
       
  6750 
       
  6751             if (bindings["start"] == null && bindings["date"] != null) {
       
  6752                 bindings["start"] = bindings["date"];
       
  6753             }
       
  6754 
       
  6755             // instant event: default is true. Or use values from isDuration or durationEvent
       
  6756             var instant = (bindings["isDuration"]    === null &&
       
  6757                            bindings["durationEvent"] === null) ||
       
  6758                           bindings["isDuration"] == "false" ||
       
  6759                           bindings["durationEvent"] == "false";
       
  6760 
       
  6761             var evt = new Timeline.DefaultEventSource.Event({
       
  6762                           id: bindings["id"],
       
  6763                        start: parseDateTimeFunction(bindings["start"]),
       
  6764                          end: parseDateTimeFunction(bindings["end"]),
       
  6765                  latestStart: parseDateTimeFunction(bindings["latestStart"]),
       
  6766                  earliestEnd: parseDateTimeFunction(bindings["earliestEnd"]),
       
  6767                      instant: instant, // instant
       
  6768                         text: bindings["title"], // text
       
  6769                  description: bindings["description"],
       
  6770                        image: this._resolveRelativeURL(bindings["image"], base),
       
  6771                         link: this._resolveRelativeURL(bindings["link"] , base),
       
  6772                         icon: this._resolveRelativeURL(bindings["icon"] , base),
       
  6773                        color: bindings["color"],
       
  6774                    textColor: bindings["textColor"],
       
  6775                    hoverText: bindings["hoverText"],
       
  6776                      caption: bindings["caption"],
       
  6777                    classname: bindings["classname"],
       
  6778                    tapeImage: bindings["tapeImage"],
       
  6779                   tapeRepeat: bindings["tapeRepeat"],
       
  6780                      eventID: bindings["eventID"],
       
  6781                     trackNum: bindings["trackNum"]
       
  6782             });
       
  6783             evt._bindings = bindings;
       
  6784             evt.getProperty = function(name) {
       
  6785                 return this._bindings[name];
       
  6786             };
       
  6787             evt.setWikiInfo(wikiURL, wikiSection);
       
  6788 
       
  6789             this._events.add(evt);
       
  6790             added = true;
       
  6791         }
       
  6792         node = node.nextSibling;
       
  6793     }
       
  6794 
       
  6795     if (added) {
       
  6796         this._fire("onAddMany", []);
       
  6797     }
       
  6798 };
       
  6799 
       
  6800 Timeline.DefaultEventSource.prototype.add = function(evt) {
       
  6801     this._events.add(evt);
       
  6802     this._fire("onAddOne", [evt]);
       
  6803 };
       
  6804 
       
  6805 Timeline.DefaultEventSource.prototype.addMany = function(events) {
       
  6806     for (var i = 0; i < events.length; i++) {
       
  6807         this._events.add(events[i]);
       
  6808     }
       
  6809     this._fire("onAddMany", []);
       
  6810 };
       
  6811 
       
  6812 Timeline.DefaultEventSource.prototype.clear = function() {
       
  6813     this._events.removeAll();
       
  6814     this._fire("onClear", []);
       
  6815 };
       
  6816 
       
  6817 Timeline.DefaultEventSource.prototype.getEvent = function(id) {
       
  6818     return this._events.getEvent(id);
       
  6819 };
       
  6820 
       
  6821 Timeline.DefaultEventSource.prototype.getEventIterator = function(startDate, endDate) {
       
  6822     return this._events.getIterator(startDate, endDate);
       
  6823 };
       
  6824 
       
  6825 Timeline.DefaultEventSource.prototype.getEventReverseIterator = function(startDate, endDate) {
       
  6826     return this._events.getReverseIterator(startDate, endDate);
       
  6827 };
       
  6828 
       
  6829 Timeline.DefaultEventSource.prototype.getAllEventIterator = function() {
       
  6830     return this._events.getAllIterator();
       
  6831 };
       
  6832 
       
  6833 Timeline.DefaultEventSource.prototype.getCount = function() {
       
  6834     return this._events.getCount();
       
  6835 };
       
  6836 
       
  6837 Timeline.DefaultEventSource.prototype.getEarliestDate = function() {
       
  6838     return this._events.getEarliestDate();
       
  6839 };
       
  6840 
       
  6841 Timeline.DefaultEventSource.prototype.getLatestDate = function() {
       
  6842     return this._events.getLatestDate();
       
  6843 };
       
  6844 
       
  6845 Timeline.DefaultEventSource.prototype._fire = function(handlerName, args) {
       
  6846     for (var i = 0; i < this._listeners.length; i++) {
       
  6847         var listener = this._listeners[i];
       
  6848         if (handlerName in listener) {
       
  6849             try {
       
  6850                 listener[handlerName].apply(listener, args);
       
  6851             } catch (e) {
       
  6852                 SimileAjax.Debug.exception(e);
       
  6853             }
       
  6854         }
       
  6855     }
       
  6856 };
       
  6857 
       
  6858 Timeline.DefaultEventSource.prototype._getBaseURL = function(url) {
       
  6859     if (url.indexOf("://") < 0) {
       
  6860         var url2 = this._getBaseURL(document.location.href);
       
  6861         if (url.substr(0,1) == "/") {
       
  6862             url = url2.substr(0, url2.indexOf("/", url2.indexOf("://") + 3)) + url;
       
  6863         } else {
       
  6864             url = url2 + url;
       
  6865         }
       
  6866     }
       
  6867 
       
  6868     var i = url.lastIndexOf("/");
       
  6869     if (i < 0) {
       
  6870         return "";
       
  6871     } else {
       
  6872         return url.substr(0, i+1);
       
  6873     }
       
  6874 };
       
  6875 
       
  6876 Timeline.DefaultEventSource.prototype._resolveRelativeURL = function(url, base) {
       
  6877     if (url == null || url == "") {
       
  6878         return url;
       
  6879     } else if (url.indexOf("://") > 0) {
       
  6880         return url;
       
  6881     } else if (url.substr(0,1) == "/") {
       
  6882         return base.substr(0, base.indexOf("/", base.indexOf("://") + 3)) + url;
       
  6883     } else {
       
  6884         return base + url;
       
  6885     }
       
  6886 };
       
  6887 
       
  6888 
       
  6889 Timeline.DefaultEventSource.Event = function(args) {
       
  6890   //
       
  6891   // Attention developers!
       
  6892   // If you add a new event attribute, please be sure to add it to
       
  6893   // all three load functions: loadXML, loadSPARCL, loadJSON.
       
  6894   // Thanks!
       
  6895   //
       
  6896   // args is a hash/object. It supports the following keys. Most are optional
       
  6897   //   id            -- an internal id. Really shouldn't be used by events.
       
  6898   //                    Timeline library clients should use eventID
       
  6899   //   eventID       -- For use by library client when writing custom painters or
       
  6900   //                    custom fillInfoBubble
       
  6901   //   start
       
  6902   //   end
       
  6903   //   latestStart
       
  6904   //   earliestEnd
       
  6905   //   instant      -- boolean. Controls precise/non-precise logic & duration/instant issues
       
  6906   //   text         -- event source attribute 'title' -- used as the label on Timelines and in bubbles.
       
  6907   //   description  -- used in bubbles
       
  6908   //   image        -- used in bubbles
       
  6909   //   link         -- used in bubbles
       
  6910   //   icon         -- on the Timeline
       
  6911   //   color        -- Timeline label and tape color
       
  6912   //   textColor    -- Timeline label color, overrides color attribute
       
  6913   //   hoverText    -- deprecated, here for backwards compatibility.
       
  6914   //                   Superceeded by caption
       
  6915   //   caption      -- tooltip-like caption on the Timeline. Uses HTML title attribute
       
  6916   //   classname    -- used to set classname in Timeline. Enables better CSS selector rules
       
  6917   //   tapeImage    -- background image of the duration event's tape div on the Timeline
       
  6918   //   tapeRepeat   -- repeat attribute for tapeImage. {repeat | repeat-x | repeat-y }
       
  6919 
       
  6920   function cleanArg(arg) {
       
  6921       // clean up an arg
       
  6922       return (args[arg] != null && args[arg] != "") ? args[arg] : null;
       
  6923   }
       
  6924 
       
  6925   var id = args.id ? args.id.trim() : "";
       
  6926   this._id = id.length > 0 ? id : Timeline.EventUtils.getNewEventID();
       
  6927 
       
  6928   this._instant = args.instant || (args.end == null);
       
  6929 
       
  6930   this._start = args.start;
       
  6931   this._end = (args.end != null) ? args.end : args.start;
       
  6932 
       
  6933   this._latestStart = (args.latestStart != null) ?
       
  6934                        args.latestStart : (args.instant ? this._end : this._start);
       
  6935   this._earliestEnd = (args.earliestEnd != null) ? args.earliestEnd : this._end;
       
  6936 
       
  6937   // check sanity of dates since incorrect dates will later cause calculation errors
       
  6938   // when painting
       
  6939   var err=[];
       
  6940   if (this._start > this._latestStart) {
       
  6941           this._latestStart = this._start;
       
  6942           err.push("start is > latestStart");}
       
  6943   if (this._start > this._earliestEnd) {
       
  6944           this._earliestEnd = this._latestStart;
       
  6945           err.push("start is > earliestEnd");}
       
  6946   if (this._start > this._end) {
       
  6947           this._end = this._earliestEnd;
       
  6948           err.push("start is > end");}
       
  6949   if (this._latestStart > this._earliestEnd) {
       
  6950           this._earliestEnd = this._latestStart;
       
  6951           err.push("latestStart is > earliestEnd");}
       
  6952   if (this._latestStart > this._end) {
       
  6953           this._end = this._earliestEnd;
       
  6954           err.push("latestStart is > end");}
       
  6955   if (this._earliestEnd > this._end) {
       
  6956           this._end = this._earliestEnd;
       
  6957           err.push("earliestEnd is > end");}
       
  6958 
       
  6959   this._eventID = cleanArg('eventID');
       
  6960   this._text = (args.text != null) ? SimileAjax.HTML.deEntify(args.text) : ""; // Change blank titles to ""
       
  6961   if (err.length > 0) {
       
  6962           this._text += " PROBLEM: " + err.join(", ");
       
  6963   }
       
  6964 
       
  6965   this._description = SimileAjax.HTML.deEntify(args.description);
       
  6966   this._image = cleanArg('image');
       
  6967   this._link =  cleanArg('link');
       
  6968   this._title = cleanArg('hoverText');
       
  6969   this._title = cleanArg('caption');
       
  6970 
       
  6971   this._icon = cleanArg('icon');
       
  6972   this._color = cleanArg('color');
       
  6973   this._textColor = cleanArg('textColor');
       
  6974   this._classname = cleanArg('classname');
       
  6975   this._tapeImage = cleanArg('tapeImage');
       
  6976   this._tapeRepeat = cleanArg('tapeRepeat');
       
  6977   this._trackNum = cleanArg('trackNum');
       
  6978   if (this._trackNum != null) {
       
  6979       this._trackNum = parseInt(this._trackNum);
       
  6980   }
       
  6981 
       
  6982   this._wikiURL = null;
       
  6983   this._wikiSection = null;
       
  6984 };
       
  6985 
       
  6986 Timeline.DefaultEventSource.Event.prototype = {
       
  6987     getID:          function() { return this._id; },
       
  6988 
       
  6989     isInstant:      function() { return this._instant; },
       
  6990     isImprecise:    function() { return this._start != this._latestStart || this._end != this._earliestEnd; },
       
  6991 
       
  6992     getStart:       function() { return this._start; },
       
  6993     getEnd:         function() { return this._end; },
       
  6994     getLatestStart: function() { return this._latestStart; },
       
  6995     getEarliestEnd: function() { return this._earliestEnd; },
       
  6996 
       
  6997     getEventID:     function() { return this._eventID; },
       
  6998     getText:        function() { return this._text; }, // title
       
  6999     getDescription: function() { return this._description; },
       
  7000     getImage:       function() { return this._image; },
       
  7001     getLink:        function() { return this._link; },
       
  7002 
       
  7003     getIcon:        function() { return this._icon; },
       
  7004     getColor:       function() { return this._color; },
       
  7005     getTextColor:   function() { return this._textColor; },
       
  7006     getClassName:   function() { return this._classname; },
       
  7007     getTapeImage:   function() { return this._tapeImage; },
       
  7008     getTapeRepeat:  function() { return this._tapeRepeat; },
       
  7009     getTrackNum:    function() { return this._trackNum; },
       
  7010 
       
  7011     getProperty:    function(name) { return null; },
       
  7012 
       
  7013     getWikiURL:     function() { return this._wikiURL; },
       
  7014     getWikiSection: function() { return this._wikiSection; },
       
  7015     setWikiInfo: function(wikiURL, wikiSection) {
       
  7016         this._wikiURL = wikiURL;
       
  7017         this._wikiSection = wikiSection;
       
  7018     },
       
  7019 
       
  7020     fillDescription: function(elmt) {
       
  7021         elmt.innerHTML = this._description;
       
  7022     },
       
  7023     fillWikiInfo: function(elmt) {
       
  7024         // Many bubbles will not support a wiki link.
       
  7025         //
       
  7026         // Strategy: assume no wiki link. If we do have
       
  7027         // enough parameters for one, then create it.
       
  7028         elmt.style.display = "none"; // default
       
  7029 
       
  7030         if (this._wikiURL == null || this._wikiSection == null) {
       
  7031           return; // EARLY RETURN
       
  7032         }
       
  7033 
       
  7034         // create the wikiID from the property or from the event text (the title)
       
  7035         var wikiID = this.getProperty("wikiID");
       
  7036         if (wikiID == null || wikiID.length == 0) {
       
  7037             wikiID = this.getText(); // use the title as the backup wiki id
       
  7038         }
       
  7039 
       
  7040         if (wikiID == null || wikiID.length == 0) {
       
  7041           return; // No wikiID. Thus EARLY RETURN
       
  7042         }
       
  7043 
       
  7044         // ready to go...
       
  7045         elmt.style.display = "inline";
       
  7046         wikiID = wikiID.replace(/\s/g, "_");
       
  7047         var url = this._wikiURL + this._wikiSection.replace(/\s/g, "_") + "/" + wikiID;
       
  7048         var a = document.createElement("a");
       
  7049         a.href = url;
       
  7050         a.target = "new";
       
  7051         a.innerHTML = Timeline.strings[Timeline.clientLocale].wikiLinkLabel;
       
  7052 
       
  7053         elmt.appendChild(document.createTextNode("["));
       
  7054         elmt.appendChild(a);
       
  7055         elmt.appendChild(document.createTextNode("]"));
       
  7056     },
       
  7057 
       
  7058     fillTime: function(elmt, labeller) {
       
  7059         if (this._instant) {
       
  7060             if (this.isImprecise()) {
       
  7061                 elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._start)));
       
  7062                 elmt.appendChild(elmt.ownerDocument.createElement("br"));
       
  7063                 elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._end)));
       
  7064             } else {
       
  7065                 elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._start)));
       
  7066             }
       
  7067         } else {
       
  7068             if (this.isImprecise()) {
       
  7069                 elmt.appendChild(elmt.ownerDocument.createTextNode(
       
  7070                     labeller.labelPrecise(this._start) + " ~ " + labeller.labelPrecise(this._latestStart)));
       
  7071                 elmt.appendChild(elmt.ownerDocument.createElement("br"));
       
  7072                 elmt.appendChild(elmt.ownerDocument.createTextNode(
       
  7073                     labeller.labelPrecise(this._earliestEnd) + " ~ " + labeller.labelPrecise(this._end)));
       
  7074             } else {
       
  7075                 elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._start)));
       
  7076                 elmt.appendChild(elmt.ownerDocument.createElement("br"));
       
  7077                 elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._end)));
       
  7078             }
       
  7079         }
       
  7080     },
       
  7081 
       
  7082     fillInfoBubble: function(elmt, theme, labeller) {
       
  7083         var doc = elmt.ownerDocument;
       
  7084 
       
  7085         var title = this.getText();
       
  7086         var link = this.getLink();
       
  7087         var image = this.getImage();
       
  7088 
       
  7089         if (image != null) {
       
  7090             var img = doc.createElement("img");
       
  7091             img.src = image;
       
  7092 
       
  7093             theme.event.bubble.imageStyler(img);
       
  7094             elmt.appendChild(img);
       
  7095         }
       
  7096 
       
  7097         var divTitle = doc.createElement("div");
       
  7098         var textTitle = doc.createTextNode(title);
       
  7099         if (link != null) {
       
  7100             var a = doc.createElement("a");
       
  7101             a.href = link;
       
  7102             a.appendChild(textTitle);
       
  7103             divTitle.appendChild(a);
       
  7104         } else {
       
  7105             divTitle.appendChild(textTitle);
       
  7106         }
       
  7107         theme.event.bubble.titleStyler(divTitle);
       
  7108         elmt.appendChild(divTitle);
       
  7109 
       
  7110         var divBody = doc.createElement("div");
       
  7111         this.fillDescription(divBody);
       
  7112         theme.event.bubble.bodyStyler(divBody);
       
  7113         elmt.appendChild(divBody);
       
  7114 
       
  7115         var divTime = doc.createElement("div");
       
  7116         this.fillTime(divTime, labeller);
       
  7117         theme.event.bubble.timeStyler(divTime);
       
  7118         elmt.appendChild(divTime);
       
  7119 
       
  7120         var divWiki = doc.createElement("div");
       
  7121         this.fillWikiInfo(divWiki);
       
  7122         theme.event.bubble.wikiStyler(divWiki);
       
  7123         elmt.appendChild(divWiki);
       
  7124     }
       
  7125 };
       
  7126 
       
  7127 
       
  7128 /*==================================================
       
  7129  *  Original Event Painter
       
  7130  *==================================================
       
  7131  */
       
  7132 
       
  7133 /*==================================================
       
  7134  *
       
  7135  * To enable a single event listener to monitor everything
       
  7136  * on a Timeline, we need a way to map from an event's icon,
       
  7137  * label or tape element to the associated timeline, band and
       
  7138  * specific event.
       
  7139  *
       
  7140  * Thus a set format is used for the id's of the
       
  7141  * events' elements on the Timeline--
       
  7142  *
       
  7143  * element id format for labels, icons, tapes:
       
  7144  *   labels: label-tl-<timelineID>-<band_index>-<evt.id>
       
  7145  *    icons: icon-tl-<timelineID>-<band_index>-<evt.id>
       
  7146  *    tapes: tape1-tl-<timelineID>-<band_index>-<evt.id>
       
  7147  *           tape2-tl-<timelineID>-<band_index>-<evt.id>
       
  7148  *           // some events have more than one tape
       
  7149  *    highlight: highlight1-tl-<timelineID>-<band_index>-<evt.id>
       
  7150  *               highlight2-tl-<timelineID>-<band_index>-<evt.id>
       
  7151  *           // some events have more than one highlight div (future)
       
  7152  * You can then retrieve the band/timeline objects and event object
       
  7153  * by using Timeline.EventUtils.decodeEventElID
       
  7154  *
       
  7155  *==================================================
       
  7156  */
       
  7157 
       
  7158 /*
       
  7159  *    eventPaintListener functions receive calls about painting.
       
  7160  *    function(band, op, evt, els)
       
  7161  *       context: 'this' will be an OriginalEventPainter object.
       
  7162  *                It has properties and methods for obtaining
       
  7163  *                the relevant band, timeline, etc
       
  7164  *       band = the band being painted
       
  7165  *       op = 'paintStarting' // the painter is about to remove
       
  7166  *            all previously painted events, if any. It will
       
  7167  *            then start painting all of the visible events that
       
  7168  *            pass the filter.
       
  7169  *            evt = null, els = null
       
  7170  *       op = 'paintEnded' // the painter has finished painting
       
  7171  *            all of the visible events that passed the filter
       
  7172  *            evt = null, els = null
       
  7173  *       op = 'paintedEvent' // the painter just finished painting an event
       
  7174  *            evt = event just painted
       
  7175  *            els = array of painted elements' divs. Depending on the event,
       
  7176  *                  the array could be just a tape or icon (if no label).
       
  7177  *                  Or could include label, multiple tape divs (imprecise event),
       
  7178  *                  highlight divs. The array is not ordered. The meaning of
       
  7179  *                  each el is available by decoding the el's id
       
  7180  *      Note that there may be no paintedEvent calls if no events were visible
       
  7181  *      or passed the filter.
       
  7182  */
       
  7183 
       
  7184 Timeline.OriginalEventPainter = function(params) {
       
  7185     this._params = params;
       
  7186     this._onSelectListeners = [];
       
  7187     this._eventPaintListeners = [];
       
  7188 
       
  7189     this._filterMatcher = null;
       
  7190     this._highlightMatcher = null;
       
  7191     this._frc = null;
       
  7192 
       
  7193     this._eventIdToElmt = {};
       
  7194 };
       
  7195 
       
  7196 Timeline.OriginalEventPainter.prototype.initialize = function(band, timeline) {
       
  7197     this._band = band;
       
  7198     this._timeline = timeline;
       
  7199 
       
  7200     this._backLayer = null;
       
  7201     this._eventLayer = null;
       
  7202     this._lineLayer = null;
       
  7203     this._highlightLayer = null;
       
  7204 
       
  7205     this._eventIdToElmt = null;
       
  7206 };
       
  7207 
       
  7208 Timeline.OriginalEventPainter.prototype.getType = function() {
       
  7209     return 'original';
       
  7210 };
       
  7211 
       
  7212 Timeline.OriginalEventPainter.prototype.addOnSelectListener = function(listener) {
       
  7213     this._onSelectListeners.push(listener);
       
  7214 };
       
  7215 
       
  7216 Timeline.OriginalEventPainter.prototype.removeOnSelectListener = function(listener) {
       
  7217     for (var i = 0; i < this._onSelectListeners.length; i++) {
       
  7218         if (this._onSelectListeners[i] == listener) {
       
  7219             this._onSelectListeners.splice(i, 1);
       
  7220             break;
       
  7221         }
       
  7222     }
       
  7223 };
       
  7224 
       
  7225 Timeline.OriginalEventPainter.prototype.addEventPaintListener = function(listener) {
       
  7226     this._eventPaintListeners.push(listener);
       
  7227 };
       
  7228 
       
  7229 Timeline.OriginalEventPainter.prototype.removeEventPaintListener = function(listener) {
       
  7230     for (var i = 0; i < this._eventPaintListeners.length; i++) {
       
  7231         if (this._eventPaintListeners[i] == listener) {
       
  7232             this._eventPaintListeners.splice(i, 1);
       
  7233             break;
       
  7234         }
       
  7235     }
       
  7236 };
       
  7237 
       
  7238 Timeline.OriginalEventPainter.prototype.getFilterMatcher = function() {
       
  7239     return this._filterMatcher;
       
  7240 };
       
  7241 
       
  7242 Timeline.OriginalEventPainter.prototype.setFilterMatcher = function(filterMatcher) {
       
  7243     this._filterMatcher = filterMatcher;
       
  7244 };
       
  7245 
       
  7246 Timeline.OriginalEventPainter.prototype.getHighlightMatcher = function() {
       
  7247     return this._highlightMatcher;
       
  7248 };
       
  7249 
       
  7250 Timeline.OriginalEventPainter.prototype.setHighlightMatcher = function(highlightMatcher) {
       
  7251     this._highlightMatcher = highlightMatcher;
       
  7252 };
       
  7253 
       
  7254 Timeline.OriginalEventPainter.prototype.paint = function() {
       
  7255     // Paints the events for a given section of the band--what is
       
  7256     // visible on screen and some extra.
       
  7257     var eventSource = this._band.getEventSource();
       
  7258     if (eventSource == null) {
       
  7259         return;
       
  7260     }
       
  7261 
       
  7262     this._eventIdToElmt = {};
       
  7263     this._fireEventPaintListeners('paintStarting', null, null);
       
  7264     this._prepareForPainting();
       
  7265 
       
  7266     var metrics = this._computeMetrics();
       
  7267     var minDate = this._band.getMinDate();
       
  7268     var maxDate = this._band.getMaxDate();
       
  7269 
       
  7270     var filterMatcher = (this._filterMatcher != null) ?
       
  7271         this._filterMatcher :
       
  7272         function(evt) { return true; };
       
  7273     var highlightMatcher = (this._highlightMatcher != null) ?
       
  7274         this._highlightMatcher :
       
  7275         function(evt) { return -1; };
       
  7276 
       
  7277     var iterator = eventSource.getEventReverseIterator(minDate, maxDate);
       
  7278     while (iterator.hasNext()) {
       
  7279         var evt = iterator.next();
       
  7280         if (filterMatcher(evt)) {
       
  7281             this.paintEvent(evt, metrics, this._params.theme, highlightMatcher(evt));
       
  7282         }
       
  7283     }
       
  7284 
       
  7285     this._highlightLayer.style.display = "block";
       
  7286     this._lineLayer.style.display = "block";
       
  7287     this._eventLayer.style.display = "block";
       
  7288     // update the band object for max number of tracks in this section of the ether
       
  7289     this._band.updateEventTrackInfo(this._tracks.length, metrics.trackIncrement);
       
  7290     this._fireEventPaintListeners('paintEnded', null, null);
       
  7291 
       
  7292     this._setOrthogonalOffset(metrics);
       
  7293 };
       
  7294 
       
  7295 Timeline.OriginalEventPainter.prototype.softPaint = function() {
       
  7296     this._setOrthogonalOffset(this._computeMetrics());
       
  7297 };
       
  7298 
       
  7299 Timeline.OriginalEventPainter.prototype._setOrthogonalOffset = function(metrics) {
       
  7300     var actualViewWidth = 2 * metrics.trackOffset + this._tracks.length * metrics.trackIncrement;
       
  7301     var minOrthogonalOffset = Math.min(0, this._band.getViewWidth() - actualViewWidth);
       
  7302     var orthogonalOffset = Math.max(minOrthogonalOffset, this._band.getViewOrthogonalOffset());
       
  7303 
       
  7304     this._highlightLayer.style.top =
       
  7305         this._lineLayer.style.top =
       
  7306             this._eventLayer.style.top =
       
  7307                 orthogonalOffset + "px";
       
  7308 };
       
  7309 
       
  7310 Timeline.OriginalEventPainter.prototype._computeMetrics = function() {
       
  7311      var eventTheme = this._params.theme.event;
       
  7312      var trackHeight = Math.max(eventTheme.track.height, eventTheme.tape.height +
       
  7313                          this._frc.getLineHeight());
       
  7314      var metrics = {
       
  7315             trackOffset: eventTheme.track.offset,
       
  7316             trackHeight: trackHeight,
       
  7317                trackGap: eventTheme.track.gap,
       
  7318          trackIncrement: trackHeight + eventTheme.track.gap,
       
  7319                    icon: eventTheme.instant.icon,
       
  7320               iconWidth: eventTheme.instant.iconWidth,
       
  7321              iconHeight: eventTheme.instant.iconHeight,
       
  7322              labelWidth: eventTheme.label.width,
       
  7323            maxLabelChar: eventTheme.label.maxLabelChar,
       
  7324     impreciseIconMargin: eventTheme.instant.impreciseIconMargin
       
  7325      };
       
  7326 
       
  7327      return metrics;
       
  7328 };
       
  7329 
       
  7330 Timeline.OriginalEventPainter.prototype._prepareForPainting = function() {
       
  7331     // Remove everything previously painted: highlight, line and event layers.
       
  7332     // Prepare blank layers for painting.
       
  7333     var band = this._band;
       
  7334 
       
  7335     if (this._backLayer == null) {
       
  7336         this._backLayer = this._band.createLayerDiv(0, "timeline-band-events");
       
  7337         this._backLayer.style.visibility = "hidden";
       
  7338 
       
  7339         var eventLabelPrototype = document.createElement("span");
       
  7340         eventLabelPrototype.className = "timeline-event-label";
       
  7341         this._backLayer.appendChild(eventLabelPrototype);
       
  7342         this._frc = SimileAjax.Graphics.getFontRenderingContext(eventLabelPrototype);
       
  7343     }
       
  7344     this._frc.update();
       
  7345     this._tracks = [];
       
  7346 
       
  7347     if (this._highlightLayer != null) {
       
  7348         band.removeLayerDiv(this._highlightLayer);
       
  7349     }
       
  7350     this._highlightLayer = band.createLayerDiv(105, "timeline-band-highlights");
       
  7351     this._highlightLayer.style.display = "none";
       
  7352 
       
  7353     if (this._lineLayer != null) {
       
  7354         band.removeLayerDiv(this._lineLayer);
       
  7355     }
       
  7356     this._lineLayer = band.createLayerDiv(110, "timeline-band-lines");
       
  7357     this._lineLayer.style.display = "none";
       
  7358 
       
  7359     if (this._eventLayer != null) {
       
  7360         band.removeLayerDiv(this._eventLayer);
       
  7361     }
       
  7362     this._eventLayer = band.createLayerDiv(115, "timeline-band-events");
       
  7363     this._eventLayer.style.display = "none";
       
  7364 };
       
  7365 
       
  7366 Timeline.OriginalEventPainter.prototype.paintEvent = function(evt, metrics, theme, highlightIndex) {
       
  7367     if (evt.isInstant()) {
       
  7368         this.paintInstantEvent(evt, metrics, theme, highlightIndex);
       
  7369     } else {
       
  7370         this.paintDurationEvent(evt, metrics, theme, highlightIndex);
       
  7371     }
       
  7372 };
       
  7373 
       
  7374 Timeline.OriginalEventPainter.prototype.paintInstantEvent = function(evt, metrics, theme, highlightIndex) {
       
  7375     if (evt.isImprecise()) {
       
  7376         this.paintImpreciseInstantEvent(evt, metrics, theme, highlightIndex);
       
  7377     } else {
       
  7378         this.paintPreciseInstantEvent(evt, metrics, theme, highlightIndex);
       
  7379     }
       
  7380 }
       
  7381 
       
  7382 Timeline.OriginalEventPainter.prototype.paintDurationEvent = function(evt, metrics, theme, highlightIndex) {
       
  7383     if (evt.isImprecise()) {
       
  7384         this.paintImpreciseDurationEvent(evt, metrics, theme, highlightIndex);
       
  7385     } else {
       
  7386         this.paintPreciseDurationEvent(evt, metrics, theme, highlightIndex);
       
  7387     }
       
  7388 }
       
  7389 
       
  7390 Timeline.OriginalEventPainter.prototype.paintPreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
       
  7391     var doc = this._timeline.getDocument();
       
  7392     var text = evt.getText();
       
  7393 
       
  7394     var startDate = evt.getStart();
       
  7395     var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
       
  7396     var iconRightEdge = Math.round(startPixel + metrics.iconWidth / 2);
       
  7397     var iconLeftEdge = Math.round(startPixel - metrics.iconWidth / 2);
       
  7398 
       
  7399     var labelDivClassName = this._getLabelDivClassName(evt);
       
  7400     var labelSize = this._frc.computeSize(text, labelDivClassName);
       
  7401     var labelLeft = iconRightEdge + theme.event.label.offsetFromLine;
       
  7402     var labelRight = labelLeft + labelSize.width;
       
  7403 
       
  7404     var rightEdge = labelRight;
       
  7405     var track = this._findFreeTrack(evt, rightEdge);
       
  7406 
       
  7407     var labelTop = Math.round(
       
  7408         metrics.trackOffset + track * metrics.trackIncrement +
       
  7409         metrics.trackHeight / 2 - labelSize.height / 2);
       
  7410 
       
  7411     var iconElmtData = this._paintEventIcon(evt, track, iconLeftEdge, metrics, theme, 0);
       
  7412     var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width,
       
  7413         labelSize.height, theme, labelDivClassName, highlightIndex);
       
  7414     var els = [iconElmtData.elmt, labelElmtData.elmt];
       
  7415 
       
  7416     var self = this;
       
  7417     var clickHandler = function(elmt, domEvt, target) {
       
  7418         return self._onClickInstantEvent(iconElmtData.elmt, domEvt, evt);
       
  7419     };
       
  7420     SimileAjax.DOM.registerEvent(iconElmtData.elmt, "mousedown", clickHandler);
       
  7421     SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
       
  7422 
       
  7423     var hDiv = this._createHighlightDiv(highlightIndex, iconElmtData, theme, evt);
       
  7424     if (hDiv != null) {els.push(hDiv);}
       
  7425     this._fireEventPaintListeners('paintedEvent', evt, els);
       
  7426 
       
  7427 
       
  7428     this._eventIdToElmt[evt.getID()] = iconElmtData.elmt;
       
  7429     this._tracks[track] = iconLeftEdge;
       
  7430 };
       
  7431 
       
  7432 Timeline.OriginalEventPainter.prototype.paintImpreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
       
  7433     var doc = this._timeline.getDocument();
       
  7434     var text = evt.getText();
       
  7435 
       
  7436     var startDate = evt.getStart();
       
  7437     var endDate = evt.getEnd();
       
  7438     var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
       
  7439     var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
       
  7440 
       
  7441     var iconRightEdge = Math.round(startPixel + metrics.iconWidth / 2);
       
  7442     var iconLeftEdge = Math.round(startPixel - metrics.iconWidth / 2);
       
  7443 
       
  7444     var labelDivClassName = this._getLabelDivClassName(evt);
       
  7445     var labelSize = this._frc.computeSize(text, labelDivClassName);
       
  7446     var labelLeft = iconRightEdge + theme.event.label.offsetFromLine;
       
  7447     var labelRight = labelLeft + labelSize.width;
       
  7448 
       
  7449     var rightEdge = Math.max(labelRight, endPixel);
       
  7450     var track = this._findFreeTrack(evt, rightEdge);
       
  7451     var tapeHeight = theme.event.tape.height;
       
  7452     var labelTop = Math.round(
       
  7453         metrics.trackOffset + track * metrics.trackIncrement + tapeHeight);
       
  7454 
       
  7455     var iconElmtData = this._paintEventIcon(evt, track, iconLeftEdge, metrics, theme, tapeHeight);
       
  7456     var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width,
       
  7457                         labelSize.height, theme, labelDivClassName, highlightIndex);
       
  7458 
       
  7459     var color = evt.getColor();
       
  7460     color = color != null ? color : theme.event.instant.impreciseColor;
       
  7461 
       
  7462     var tapeElmtData = this._paintEventTape(evt, track, startPixel, endPixel,
       
  7463         color, theme.event.instant.impreciseOpacity, metrics, theme, 0);
       
  7464     var els = [iconElmtData.elmt, labelElmtData.elmt, tapeElmtData.elmt];
       
  7465 
       
  7466     var self = this;
       
  7467     var clickHandler = function(elmt, domEvt, target) {
       
  7468         return self._onClickInstantEvent(iconElmtData.elmt, domEvt, evt);
       
  7469     };
       
  7470     SimileAjax.DOM.registerEvent(iconElmtData.elmt, "mousedown", clickHandler);
       
  7471     SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
       
  7472     SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
       
  7473 
       
  7474     var hDiv = this._createHighlightDiv(highlightIndex, iconElmtData, theme, evt);
       
  7475     if (hDiv != null) {els.push(hDiv);}
       
  7476     this._fireEventPaintListeners('paintedEvent', evt, els);
       
  7477 
       
  7478     this._eventIdToElmt[evt.getID()] = iconElmtData.elmt;
       
  7479     this._tracks[track] = iconLeftEdge;
       
  7480 };
       
  7481 
       
  7482 Timeline.OriginalEventPainter.prototype.paintPreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
       
  7483     var doc = this._timeline.getDocument();
       
  7484     var text = evt.getText();
       
  7485 
       
  7486     var startDate = evt.getStart();
       
  7487     var endDate = evt.getEnd();
       
  7488     var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
       
  7489     var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
       
  7490 
       
  7491     var labelDivClassName = this._getLabelDivClassName(evt);
       
  7492     var labelSize = this._frc.computeSize(text, labelDivClassName);
       
  7493     var labelLeft = startPixel;
       
  7494     var labelRight = labelLeft + labelSize.width;
       
  7495 
       
  7496     var rightEdge = Math.max(labelRight, endPixel);
       
  7497     var track = this._findFreeTrack(evt, rightEdge);
       
  7498     var labelTop = Math.round(
       
  7499         metrics.trackOffset + track * metrics.trackIncrement + theme.event.tape.height);
       
  7500 
       
  7501     var color = evt.getColor();
       
  7502     color = color != null ? color : theme.event.duration.color;
       
  7503 
       
  7504     var tapeElmtData = this._paintEventTape(evt, track, startPixel, endPixel, color, 100, metrics, theme, 0);
       
  7505     var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width,
       
  7506       labelSize.height, theme, labelDivClassName, highlightIndex);
       
  7507     var els = [tapeElmtData.elmt, labelElmtData.elmt];
       
  7508 
       
  7509     var self = this;
       
  7510     var clickHandler = function(elmt, domEvt, target) {
       
  7511         return self._onClickDurationEvent(tapeElmtData.elmt, domEvt, evt);
       
  7512     };
       
  7513     SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
       
  7514     SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
       
  7515 
       
  7516     var hDiv = this._createHighlightDiv(highlightIndex, tapeElmtData, theme, evt);
       
  7517     if (hDiv != null) {els.push(hDiv);}
       
  7518     this._fireEventPaintListeners('paintedEvent', evt, els);
       
  7519 
       
  7520     this._eventIdToElmt[evt.getID()] = tapeElmtData.elmt;
       
  7521     this._tracks[track] = startPixel;
       
  7522 };
       
  7523 
       
  7524 Timeline.OriginalEventPainter.prototype.paintImpreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
       
  7525     var doc = this._timeline.getDocument();
       
  7526     var text = evt.getText();
       
  7527 
       
  7528     var startDate = evt.getStart();
       
  7529     var latestStartDate = evt.getLatestStart();
       
  7530     var endDate = evt.getEnd();
       
  7531     var earliestEndDate = evt.getEarliestEnd();
       
  7532 
       
  7533     var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
       
  7534     var latestStartPixel = Math.round(this._band.dateToPixelOffset(latestStartDate));
       
  7535     var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
       
  7536     var earliestEndPixel = Math.round(this._band.dateToPixelOffset(earliestEndDate));
       
  7537 
       
  7538     var labelDivClassName = this._getLabelDivClassName(evt);
       
  7539     var labelSize = this._frc.computeSize(text, labelDivClassName);
       
  7540     var labelLeft = latestStartPixel;
       
  7541     var labelRight = labelLeft + labelSize.width;
       
  7542 
       
  7543     var rightEdge = Math.max(labelRight, endPixel);
       
  7544     var track = this._findFreeTrack(evt, rightEdge);
       
  7545     var labelTop = Math.round(
       
  7546         metrics.trackOffset + track * metrics.trackIncrement + theme.event.tape.height);
       
  7547 
       
  7548     var color = evt.getColor();
       
  7549     color = color != null ? color : theme.event.duration.color;
       
  7550 
       
  7551     // Imprecise events can have two event tapes
       
  7552     // The imprecise dates tape, uses opacity to be dimmer than precise dates
       
  7553     var impreciseTapeElmtData = this._paintEventTape(evt, track, startPixel, endPixel,
       
  7554         theme.event.duration.impreciseColor,
       
  7555         theme.event.duration.impreciseOpacity, metrics, theme, 0);
       
  7556     // The precise dates tape, regular (100%) opacity
       
  7557     var tapeElmtData = this._paintEventTape(evt, track, latestStartPixel,
       
  7558         earliestEndPixel, color, 100, metrics, theme, 1);
       
  7559 
       
  7560     var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop,
       
  7561         labelSize.width, labelSize.height, theme, labelDivClassName, highlightIndex);
       
  7562     var els = [impreciseTapeElmtData.elmt, tapeElmtData.elmt, labelElmtData.elmt];
       
  7563 
       
  7564     var self = this;
       
  7565     var clickHandler = function(elmt, domEvt, target) {
       
  7566         return self._onClickDurationEvent(tapeElmtData.elmt, domEvt, evt);
       
  7567     };
       
  7568     SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
       
  7569     SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
       
  7570 
       
  7571     var hDiv = this._createHighlightDiv(highlightIndex, tapeElmtData, theme, evt);
       
  7572     if (hDiv != null) {els.push(hDiv);}
       
  7573     this._fireEventPaintListeners('paintedEvent', evt, els);
       
  7574 
       
  7575     this._eventIdToElmt[evt.getID()] = tapeElmtData.elmt;
       
  7576     this._tracks[track] = startPixel;
       
  7577 };
       
  7578 
       
  7579 Timeline.OriginalEventPainter.prototype._encodeEventElID = function(elType, evt) {
       
  7580     return Timeline.EventUtils.encodeEventElID(this._timeline, this._band, elType, evt);
       
  7581 };
       
  7582 
       
  7583 Timeline.OriginalEventPainter.prototype._findFreeTrack = function(event, rightEdge) {
       
  7584     var trackAttribute = event.getTrackNum();
       
  7585     if (trackAttribute != null) {
       
  7586         return trackAttribute; // early return since event includes track number
       
  7587     }
       
  7588 
       
  7589     // normal case: find an open track
       
  7590     for (var i = 0; i < this._tracks.length; i++) {
       
  7591         var t = this._tracks[i];
       
  7592         if (t > rightEdge) {
       
  7593             break;
       
  7594         }
       
  7595     }
       
  7596     return i;
       
  7597 };
       
  7598 
       
  7599 Timeline.OriginalEventPainter.prototype._paintEventIcon = function(evt, iconTrack, left, metrics, theme, tapeHeight) {
       
  7600     // If no tape, then paint the icon in the middle of the track.
       
  7601     // If there is a tape, paint the icon below the tape + impreciseIconMargin
       
  7602     var icon = evt.getIcon();
       
  7603     icon = icon != null ? icon : metrics.icon;
       
  7604 
       
  7605     var top; // top of the icon
       
  7606     if (tapeHeight > 0) {
       
  7607         top = metrics.trackOffset + iconTrack * metrics.trackIncrement +
       
  7608               tapeHeight + metrics.impreciseIconMargin;
       
  7609     } else {
       
  7610         var middle = metrics.trackOffset + iconTrack * metrics.trackIncrement +
       
  7611                      metrics.trackHeight / 2;
       
  7612         top = Math.round(middle - metrics.iconHeight / 2);
       
  7613     }
       
  7614     var img = SimileAjax.Graphics.createTranslucentImage(icon);
       
  7615     var iconDiv = this._timeline.getDocument().createElement("div");
       
  7616     iconDiv.className = this._getElClassName('timeline-event-icon', evt, 'icon');
       
  7617     iconDiv.id = this._encodeEventElID('icon', evt);
       
  7618     iconDiv.style.left = left + "px";
       
  7619     iconDiv.style.top = top + "px";
       
  7620     iconDiv.appendChild(img);
       
  7621 
       
  7622     if(evt._title != null)
       
  7623         iconDiv.title = evt._title;
       
  7624 
       
  7625     this._eventLayer.appendChild(iconDiv);
       
  7626 
       
  7627     return {
       
  7628         left:   left,
       
  7629         top:    top,
       
  7630         width:  metrics.iconWidth,
       
  7631         height: metrics.iconHeight,
       
  7632         elmt:   iconDiv
       
  7633     };
       
  7634 };
       
  7635 
       
  7636 Timeline.OriginalEventPainter.prototype._paintEventLabel = function(evt, text, left, top, width,
       
  7637     height, theme, labelDivClassName, highlightIndex) {
       
  7638     var doc = this._timeline.getDocument();
       
  7639 
       
  7640     var labelDiv = doc.createElement("div");
       
  7641     labelDiv.className = labelDivClassName;
       
  7642     labelDiv.id = this._encodeEventElID('label', evt);
       
  7643     labelDiv.style.left = left + "px";
       
  7644     labelDiv.style.width = width + "px";
       
  7645     labelDiv.style.top = top + "px";
       
  7646     labelDiv.innerHTML = text;
       
  7647 
       
  7648     if(evt._title != null)
       
  7649         labelDiv.title = evt._title;
       
  7650 
       
  7651     var color = evt.getTextColor();
       
  7652     if (color == null) {
       
  7653         color = evt.getColor();
       
  7654     }
       
  7655     if (color != null) {
       
  7656         labelDiv.style.color = color;
       
  7657     }
       
  7658     if (theme.event.highlightLabelBackground && highlightIndex >= 0) {
       
  7659         labelDiv.style.background = this._getHighlightColor(highlightIndex, theme);
       
  7660     }
       
  7661 
       
  7662     this._eventLayer.appendChild(labelDiv);
       
  7663 
       
  7664     return {
       
  7665         left:   left,
       
  7666         top:    top,
       
  7667         width:  width,
       
  7668         height: height,
       
  7669         elmt:   labelDiv
       
  7670     };
       
  7671 };
       
  7672 
       
  7673 Timeline.OriginalEventPainter.prototype._paintEventTape = function(
       
  7674     evt, iconTrack, startPixel, endPixel, color, opacity, metrics, theme, tape_index) {
       
  7675 
       
  7676     var tapeWidth = endPixel - startPixel;
       
  7677     var tapeHeight = theme.event.tape.height;
       
  7678     var top = metrics.trackOffset + iconTrack * metrics.trackIncrement;
       
  7679 
       
  7680     var tapeDiv = this._timeline.getDocument().createElement("div");
       
  7681     tapeDiv.className = this._getElClassName('timeline-event-tape', evt, 'tape');
       
  7682     tapeDiv.id = this._encodeEventElID('tape' + tape_index, evt);
       
  7683     tapeDiv.style.left = startPixel + "px";
       
  7684     tapeDiv.style.width = tapeWidth + "px";
       
  7685     tapeDiv.style.height = tapeHeight + "px";
       
  7686     tapeDiv.style.top = top + "px";
       
  7687 
       
  7688     if(evt._title != null)
       
  7689         tapeDiv.title = evt._title;
       
  7690 
       
  7691     if(color != null) {
       
  7692         tapeDiv.style.backgroundColor = color;
       
  7693     }
       
  7694 
       
  7695     var backgroundImage = evt.getTapeImage();
       
  7696     var backgroundRepeat = evt.getTapeRepeat();
       
  7697     backgroundRepeat = backgroundRepeat != null ? backgroundRepeat : 'repeat';
       
  7698     if(backgroundImage != null) {
       
  7699       tapeDiv.style.backgroundImage = "url(" + backgroundImage + ")";
       
  7700       tapeDiv.style.backgroundRepeat = backgroundRepeat;
       
  7701     }
       
  7702 
       
  7703     SimileAjax.Graphics.setOpacity(tapeDiv, opacity);
       
  7704 
       
  7705     this._eventLayer.appendChild(tapeDiv);
       
  7706 
       
  7707     return {
       
  7708         left:   startPixel,
       
  7709         top:    top,
       
  7710         width:  tapeWidth,
       
  7711         height: tapeHeight,
       
  7712         elmt:   tapeDiv
       
  7713     };
       
  7714 }
       
  7715 
       
  7716 Timeline.OriginalEventPainter.prototype._getLabelDivClassName = function(evt) {
       
  7717     return this._getElClassName('timeline-event-label', evt, 'label');
       
  7718 };
       
  7719 
       
  7720 Timeline.OriginalEventPainter.prototype._getElClassName = function(elClassName, evt, prefix) {
       
  7721     // Prefix and '_' is added to the event's classname. Set to null for no prefix
       
  7722     var evt_classname = evt.getClassName(),
       
  7723         pieces = [];
       
  7724 
       
  7725     if (evt_classname) {
       
  7726       if (prefix) {pieces.push(prefix + '-' + evt_classname + ' ');}
       
  7727       pieces.push(evt_classname + ' ');
       
  7728     }
       
  7729     pieces.push(elClassName);
       
  7730     return(pieces.join(''));
       
  7731 };
       
  7732 
       
  7733 Timeline.OriginalEventPainter.prototype._getHighlightColor = function(highlightIndex, theme) {
       
  7734     var highlightColors = theme.event.highlightColors;
       
  7735     return highlightColors[Math.min(highlightIndex, highlightColors.length - 1)];
       
  7736 };
       
  7737 
       
  7738 Timeline.OriginalEventPainter.prototype._createHighlightDiv = function(highlightIndex, dimensions, theme, evt) {
       
  7739     var div = null;
       
  7740     if (highlightIndex >= 0) {
       
  7741         var doc = this._timeline.getDocument();
       
  7742         var color = this._getHighlightColor(highlightIndex, theme);
       
  7743 
       
  7744         div = doc.createElement("div");
       
  7745         div.className = this._getElClassName('timeline-event-highlight', evt, 'highlight');
       
  7746         div.id = this._encodeEventElID('highlight0', evt); // in future will have other
       
  7747                                                            // highlight divs for tapes + icons
       
  7748         div.style.position = "absolute";
       
  7749         div.style.overflow = "hidden";
       
  7750         div.style.left =    (dimensions.left - 2) + "px";
       
  7751         div.style.width =   (dimensions.width + 4) + "px";
       
  7752         div.style.top =     (dimensions.top - 2) + "px";
       
  7753         div.style.height =  (dimensions.height + 4) + "px";
       
  7754         div.style.background = color;
       
  7755 
       
  7756         this._highlightLayer.appendChild(div);
       
  7757     }
       
  7758     return div;
       
  7759 };
       
  7760 
       
  7761 Timeline.OriginalEventPainter.prototype._onClickInstantEvent = function(icon, domEvt, evt) {
       
  7762     var c = SimileAjax.DOM.getPageCoordinates(icon);
       
  7763     this._showBubble(
       
  7764         c.left + Math.ceil(icon.offsetWidth / 2),
       
  7765         c.top + Math.ceil(icon.offsetHeight / 2),
       
  7766         evt
       
  7767     );
       
  7768     this._fireOnSelect(evt.getID());
       
  7769 
       
  7770     domEvt.cancelBubble = true;
       
  7771     SimileAjax.DOM.cancelEvent(domEvt);
       
  7772     return false;
       
  7773 };
       
  7774 
       
  7775 Timeline.OriginalEventPainter.prototype._onClickDurationEvent = function(target, domEvt, evt) {
       
  7776     if ("pageX" in domEvt) {
       
  7777         var x = domEvt.pageX;
       
  7778         var y = domEvt.pageY;
       
  7779     } else {
       
  7780         var c = SimileAjax.DOM.getPageCoordinates(target);
       
  7781         var x = domEvt.offsetX + c.left;
       
  7782         var y = domEvt.offsetY + c.top;
       
  7783     }
       
  7784     this._showBubble(x, y, evt);
       
  7785     this._fireOnSelect(evt.getID());
       
  7786 
       
  7787     domEvt.cancelBubble = true;
       
  7788     SimileAjax.DOM.cancelEvent(domEvt);
       
  7789     return false;
       
  7790 };
       
  7791 
       
  7792 Timeline.OriginalEventPainter.prototype.showBubble = function(evt) {
       
  7793     var elmt = this._eventIdToElmt[evt.getID()];
       
  7794     if (elmt) {
       
  7795         var c = SimileAjax.DOM.getPageCoordinates(elmt);
       
  7796         this._showBubble(c.left + elmt.offsetWidth / 2, c.top + elmt.offsetHeight / 2, evt);
       
  7797     }
       
  7798 };
       
  7799 
       
  7800 Timeline.OriginalEventPainter.prototype._showBubble = function(x, y, evt) {
       
  7801     var div = document.createElement("div");
       
  7802     var themeBubble = this._params.theme.event.bubble;
       
  7803     evt.fillInfoBubble(div, this._params.theme, this._band.getLabeller());
       
  7804 
       
  7805     SimileAjax.WindowManager.cancelPopups();
       
  7806     SimileAjax.Graphics.createBubbleForContentAndPoint(div, x, y,
       
  7807         themeBubble.width, null, themeBubble.maxHeight);
       
  7808 };
       
  7809 
       
  7810 Timeline.OriginalEventPainter.prototype._fireOnSelect = function(eventID) {
       
  7811     for (var i = 0; i < this._onSelectListeners.length; i++) {
       
  7812         this._onSelectListeners[i](eventID);
       
  7813     }
       
  7814 };
       
  7815 
       
  7816 Timeline.OriginalEventPainter.prototype._fireEventPaintListeners = function(op, evt, els) {
       
  7817     for (var i = 0; i < this._eventPaintListeners.length; i++) {
       
  7818         this._eventPaintListeners[i](this._band, op, evt, els);
       
  7819     }
       
  7820 };
       
  7821 /*==================================================
       
  7822  *  Detailed Event Painter
       
  7823  *==================================================
       
  7824  */
       
  7825 
       
  7826 // Note: a number of features from original-painter
       
  7827 //       are not yet implemented in detailed painter.
       
  7828 //       Eg classname, id attributes for icons, labels, tapes
       
  7829 
       
  7830 Timeline.DetailedEventPainter = function(params) {
       
  7831     this._params = params;
       
  7832     this._onSelectListeners = [];
       
  7833 
       
  7834     this._filterMatcher = null;
       
  7835     this._highlightMatcher = null;
       
  7836     this._frc = null;
       
  7837 
       
  7838     this._eventIdToElmt = {};
       
  7839 };
       
  7840 
       
  7841 Timeline.DetailedEventPainter.prototype.initialize = function(band, timeline) {
       
  7842     this._band = band;
       
  7843     this._timeline = timeline;
       
  7844 
       
  7845     this._backLayer = null;
       
  7846     this._eventLayer = null;
       
  7847     this._lineLayer = null;
       
  7848     this._highlightLayer = null;
       
  7849 
       
  7850     this._eventIdToElmt = null;
       
  7851 };
       
  7852 
       
  7853 Timeline.DetailedEventPainter.prototype.getType = function() {
       
  7854     return 'detailed';
       
  7855 };
       
  7856 
       
  7857 Timeline.DetailedEventPainter.prototype.addOnSelectListener = function(listener) {
       
  7858     this._onSelectListeners.push(listener);
       
  7859 };
       
  7860 
       
  7861 Timeline.DetailedEventPainter.prototype.removeOnSelectListener = function(listener) {
       
  7862     for (var i = 0; i < this._onSelectListeners.length; i++) {
       
  7863         if (this._onSelectListeners[i] == listener) {
       
  7864             this._onSelectListeners.splice(i, 1);
       
  7865             break;
       
  7866         }
       
  7867     }
       
  7868 };
       
  7869 
       
  7870 Timeline.DetailedEventPainter.prototype.getFilterMatcher = function() {
       
  7871     return this._filterMatcher;
       
  7872 };
       
  7873 
       
  7874 Timeline.DetailedEventPainter.prototype.setFilterMatcher = function(filterMatcher) {
       
  7875     this._filterMatcher = filterMatcher;
       
  7876 };
       
  7877 
       
  7878 Timeline.DetailedEventPainter.prototype.getHighlightMatcher = function() {
       
  7879     return this._highlightMatcher;
       
  7880 };
       
  7881 
       
  7882 Timeline.DetailedEventPainter.prototype.setHighlightMatcher = function(highlightMatcher) {
       
  7883     this._highlightMatcher = highlightMatcher;
       
  7884 };
       
  7885 
       
  7886 Timeline.DetailedEventPainter.prototype.paint = function() {
       
  7887     var eventSource = this._band.getEventSource();
       
  7888     if (eventSource == null) {
       
  7889         return;
       
  7890     }
       
  7891 
       
  7892     this._eventIdToElmt = {};
       
  7893     this._prepareForPainting();
       
  7894 
       
  7895     var eventTheme = this._params.theme.event;
       
  7896     var trackHeight = Math.max(eventTheme.track.height, this._frc.getLineHeight());
       
  7897     var metrics = {
       
  7898         trackOffset:    Math.round(this._band.getViewWidth() / 2 - trackHeight / 2),
       
  7899         trackHeight:    trackHeight,
       
  7900         trackGap:       eventTheme.track.gap,
       
  7901         trackIncrement: trackHeight + eventTheme.track.gap,
       
  7902         icon:           eventTheme.instant.icon,
       
  7903         iconWidth:      eventTheme.instant.iconWidth,
       
  7904         iconHeight:     eventTheme.instant.iconHeight,
       
  7905         labelWidth:     eventTheme.label.width
       
  7906     }
       
  7907 
       
  7908     var minDate = this._band.getMinDate();
       
  7909     var maxDate = this._band.getMaxDate();
       
  7910 
       
  7911     var filterMatcher = (this._filterMatcher != null) ?
       
  7912         this._filterMatcher :
       
  7913         function(evt) { return true; };
       
  7914     var highlightMatcher = (this._highlightMatcher != null) ?
       
  7915         this._highlightMatcher :
       
  7916         function(evt) { return -1; };
       
  7917 
       
  7918     var iterator = eventSource.getEventReverseIterator(minDate, maxDate);
       
  7919     while (iterator.hasNext()) {
       
  7920         var evt = iterator.next();
       
  7921         if (filterMatcher(evt)) {
       
  7922             this.paintEvent(evt, metrics, this._params.theme, highlightMatcher(evt));
       
  7923         }
       
  7924     }
       
  7925 
       
  7926     this._highlightLayer.style.display = "block";
       
  7927     this._lineLayer.style.display = "block";
       
  7928     this._eventLayer.style.display = "block";
       
  7929     // update the band object for max number of tracks in this section of the ether
       
  7930     this._band.updateEventTrackInfo(this._lowerTracks.length + this._upperTracks.length,
       
  7931                                  metrics.trackIncrement);
       
  7932 };
       
  7933 
       
  7934 Timeline.DetailedEventPainter.prototype.softPaint = function() {
       
  7935 };
       
  7936 
       
  7937 Timeline.DetailedEventPainter.prototype._prepareForPainting = function() {
       
  7938     var band = this._band;
       
  7939 
       
  7940     if (this._backLayer == null) {
       
  7941         this._backLayer = this._band.createLayerDiv(0, "timeline-band-events");
       
  7942         this._backLayer.style.visibility = "hidden";
       
  7943 
       
  7944         var eventLabelPrototype = document.createElement("span");
       
  7945         eventLabelPrototype.className = "timeline-event-label";
       
  7946         this._backLayer.appendChild(eventLabelPrototype);
       
  7947         this._frc = SimileAjax.Graphics.getFontRenderingContext(eventLabelPrototype);
       
  7948     }
       
  7949     this._frc.update();
       
  7950     this._lowerTracks = [];
       
  7951     this._upperTracks = [];
       
  7952 
       
  7953     if (this._highlightLayer != null) {
       
  7954         band.removeLayerDiv(this._highlightLayer);
       
  7955     }
       
  7956     this._highlightLayer = band.createLayerDiv(105, "timeline-band-highlights");
       
  7957     this._highlightLayer.style.display = "none";
       
  7958 
       
  7959     if (this._lineLayer != null) {
       
  7960         band.removeLayerDiv(this._lineLayer);
       
  7961     }
       
  7962     this._lineLayer = band.createLayerDiv(110, "timeline-band-lines");
       
  7963     this._lineLayer.style.display = "none";
       
  7964 
       
  7965     if (this._eventLayer != null) {
       
  7966         band.removeLayerDiv(this._eventLayer);
       
  7967     }
       
  7968     this._eventLayer = band.createLayerDiv(110, "timeline-band-events");
       
  7969     this._eventLayer.style.display = "none";
       
  7970 };
       
  7971 
       
  7972 Timeline.DetailedEventPainter.prototype.paintEvent = function(evt, metrics, theme, highlightIndex) {
       
  7973     if (evt.isInstant()) {
       
  7974         this.paintInstantEvent(evt, metrics, theme, highlightIndex);
       
  7975     } else {
       
  7976         this.paintDurationEvent(evt, metrics, theme, highlightIndex);
       
  7977     }
       
  7978 };
       
  7979 
       
  7980 Timeline.DetailedEventPainter.prototype.paintInstantEvent = function(evt, metrics, theme, highlightIndex) {
       
  7981     if (evt.isImprecise()) {
       
  7982         this.paintImpreciseInstantEvent(evt, metrics, theme, highlightIndex);
       
  7983     } else {
       
  7984         this.paintPreciseInstantEvent(evt, metrics, theme, highlightIndex);
       
  7985     }
       
  7986 }
       
  7987 
       
  7988 Timeline.DetailedEventPainter.prototype.paintDurationEvent = function(evt, metrics, theme, highlightIndex) {
       
  7989     if (evt.isImprecise()) {
       
  7990         this.paintImpreciseDurationEvent(evt, metrics, theme, highlightIndex);
       
  7991     } else {
       
  7992         this.paintPreciseDurationEvent(evt, metrics, theme, highlightIndex);
       
  7993     }
       
  7994 }
       
  7995 
       
  7996 Timeline.DetailedEventPainter.prototype.paintPreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
       
  7997     var doc = this._timeline.getDocument();
       
  7998     var text = evt.getText();
       
  7999 
       
  8000     var startDate = evt.getStart();
       
  8001     var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
       
  8002     var iconRightEdge = Math.round(startPixel + metrics.iconWidth / 2);
       
  8003     var iconLeftEdge = Math.round(startPixel - metrics.iconWidth / 2);
       
  8004 
       
  8005     var labelSize = this._frc.computeSize(text);
       
  8006     var iconTrack = this._findFreeTrackForSolid(iconRightEdge, startPixel);
       
  8007     var iconElmtData = this._paintEventIcon(evt, iconTrack, iconLeftEdge, metrics, theme);
       
  8008 
       
  8009     var labelLeft = iconRightEdge + theme.event.label.offsetFromLine;
       
  8010     var labelTrack = iconTrack;
       
  8011 
       
  8012     var iconTrackData = this._getTrackData(iconTrack);
       
  8013     if (Math.min(iconTrackData.solid, iconTrackData.text) >= labelLeft + labelSize.width) { // label on the same track, to the right of icon
       
  8014         iconTrackData.solid = iconLeftEdge;
       
  8015         iconTrackData.text = labelLeft;
       
  8016     } else { // label on a different track, below icon
       
  8017         iconTrackData.solid = iconLeftEdge;
       
  8018 
       
  8019         labelLeft = startPixel + theme.event.label.offsetFromLine;
       
  8020         labelTrack = this._findFreeTrackForText(iconTrack, labelLeft + labelSize.width, function(t) { t.line = startPixel - 2; });
       
  8021         this._getTrackData(labelTrack).text = iconLeftEdge;
       
  8022 
       
  8023         this._paintEventLine(evt, startPixel, iconTrack, labelTrack, metrics, theme);
       
  8024     }
       
  8025 
       
  8026     var labelTop = Math.round(
       
  8027         metrics.trackOffset + labelTrack * metrics.trackIncrement +
       
  8028         metrics.trackHeight / 2 - labelSize.height / 2);
       
  8029 
       
  8030     var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width, labelSize.height, theme);
       
  8031 
       
  8032     var self = this;
       
  8033     var clickHandler = function(elmt, domEvt, target) {
       
  8034         return self._onClickInstantEvent(iconElmtData.elmt, domEvt, evt);
       
  8035     };
       
  8036     SimileAjax.DOM.registerEvent(iconElmtData.elmt, "mousedown", clickHandler);
       
  8037     SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
       
  8038 
       
  8039     this._createHighlightDiv(highlightIndex, iconElmtData, theme);
       
  8040 
       
  8041     this._eventIdToElmt[evt.getID()] = iconElmtData.elmt;
       
  8042 };
       
  8043 
       
  8044 Timeline.DetailedEventPainter.prototype.paintImpreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
       
  8045     var doc = this._timeline.getDocument();
       
  8046     var text = evt.getText();
       
  8047 
       
  8048     var startDate = evt.getStart();
       
  8049     var endDate = evt.getEnd();
       
  8050     var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
       
  8051     var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
       
  8052 
       
  8053     var iconRightEdge = Math.round(startPixel + metrics.iconWidth / 2);
       
  8054     var iconLeftEdge = Math.round(startPixel - metrics.iconWidth / 2);
       
  8055 
       
  8056     var labelSize = this._frc.computeSize(text);
       
  8057     var iconTrack = this._findFreeTrackForSolid(endPixel, startPixel);
       
  8058 
       
  8059     var tapeElmtData = this._paintEventTape(evt, iconTrack, startPixel, endPixel,
       
  8060         theme.event.instant.impreciseColor, theme.event.instant.impreciseOpacity, metrics, theme);
       
  8061     var iconElmtData = this._paintEventIcon(evt, iconTrack, iconLeftEdge, metrics, theme);
       
  8062 
       
  8063     var iconTrackData = this._getTrackData(iconTrack);
       
  8064     iconTrackData.solid = iconLeftEdge;
       
  8065 
       
  8066     var labelLeft = iconRightEdge + theme.event.label.offsetFromLine;
       
  8067     var labelRight = labelLeft + labelSize.width;
       
  8068     var labelTrack;
       
  8069     if (labelRight < endPixel) {
       
  8070         labelTrack = iconTrack;
       
  8071     } else {
       
  8072         labelLeft = startPixel + theme.event.label.offsetFromLine;
       
  8073         labelRight = labelLeft + labelSize.width;
       
  8074 
       
  8075         labelTrack = this._findFreeTrackForText(iconTrack, labelRight, function(t) { t.line = startPixel - 2; });
       
  8076         this._getTrackData(labelTrack).text = iconLeftEdge;
       
  8077 
       
  8078         this._paintEventLine(evt, startPixel, iconTrack, labelTrack, metrics, theme);
       
  8079     }
       
  8080     var labelTop = Math.round(
       
  8081         metrics.trackOffset + labelTrack * metrics.trackIncrement +
       
  8082         metrics.trackHeight / 2 - labelSize.height / 2);
       
  8083 
       
  8084     var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width, labelSize.height, theme);
       
  8085 
       
  8086     var self = this;
       
  8087     var clickHandler = function(elmt, domEvt, target) {
       
  8088         return self._onClickInstantEvent(iconElmtData.elmt, domEvt, evt);
       
  8089     };
       
  8090     SimileAjax.DOM.registerEvent(iconElmtData.elmt, "mousedown", clickHandler);
       
  8091     SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
       
  8092     SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
       
  8093 
       
  8094     this._createHighlightDiv(highlightIndex, iconElmtData, theme);
       
  8095 
       
  8096     this._eventIdToElmt[evt.getID()] = iconElmtData.elmt;
       
  8097 };
       
  8098 
       
  8099 Timeline.DetailedEventPainter.prototype.paintPreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
       
  8100     var doc = this._timeline.getDocument();
       
  8101     var text = evt.getText();
       
  8102 
       
  8103     var startDate = evt.getStart();
       
  8104     var endDate = evt.getEnd();
       
  8105     var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
       
  8106     var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
       
  8107 
       
  8108     var labelSize = this._frc.computeSize(text);
       
  8109     var tapeTrack = this._findFreeTrackForSolid(endPixel);
       
  8110     var color = evt.getColor();
       
  8111     color = color != null ? color : theme.event.duration.color;
       
  8112 
       
  8113     var tapeElmtData = this._paintEventTape(evt, tapeTrack, startPixel, endPixel, color, 100, metrics, theme);
       
  8114 
       
  8115     var tapeTrackData = this._getTrackData(tapeTrack);
       
  8116     tapeTrackData.solid = startPixel;
       
  8117 
       
  8118     var labelLeft = startPixel + theme.event.label.offsetFromLine;
       
  8119     var labelTrack = this._findFreeTrackForText(tapeTrack, labelLeft + labelSize.width, function(t) { t.line = startPixel - 2; });
       
  8120     this._getTrackData(labelTrack).text = startPixel - 2;
       
  8121 
       
  8122     this._paintEventLine(evt, startPixel, tapeTrack, labelTrack, metrics, theme);
       
  8123 
       
  8124     var labelTop = Math.round(
       
  8125         metrics.trackOffset + labelTrack * metrics.trackIncrement +
       
  8126         metrics.trackHeight / 2 - labelSize.height / 2);
       
  8127 
       
  8128     var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width, labelSize.height, theme);
       
  8129 
       
  8130     var self = this;
       
  8131     var clickHandler = function(elmt, domEvt, target) {
       
  8132         return self._onClickDurationEvent(tapeElmtData.elmt, domEvt, evt);
       
  8133     };
       
  8134     SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
       
  8135     SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
       
  8136 
       
  8137     this._createHighlightDiv(highlightIndex, tapeElmtData, theme);
       
  8138 
       
  8139     this._eventIdToElmt[evt.getID()] = tapeElmtData.elmt;
       
  8140 };
       
  8141 
       
  8142 Timeline.DetailedEventPainter.prototype.paintImpreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
       
  8143     var doc = this._timeline.getDocument();
       
  8144     var text = evt.getText();
       
  8145 
       
  8146     var startDate = evt.getStart();
       
  8147     var latestStartDate = evt.getLatestStart();
       
  8148     var endDate = evt.getEnd();
       
  8149     var earliestEndDate = evt.getEarliestEnd();
       
  8150 
       
  8151     var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
       
  8152     var latestStartPixel = Math.round(this._band.dateToPixelOffset(latestStartDate));
       
  8153     var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
       
  8154     var earliestEndPixel = Math.round(this._band.dateToPixelOffset(earliestEndDate));
       
  8155 
       
  8156     var labelSize = this._frc.computeSize(text);
       
  8157     var tapeTrack = this._findFreeTrackForSolid(endPixel);
       
  8158     var color = evt.getColor();
       
  8159     color = color != null ? color : theme.event.duration.color;
       
  8160 
       
  8161     var impreciseTapeElmtData = this._paintEventTape(evt, tapeTrack, startPixel, endPixel,
       
  8162         theme.event.duration.impreciseColor, theme.event.duration.impreciseOpacity, metrics, theme);
       
  8163     var tapeElmtData = this._paintEventTape(evt, tapeTrack, latestStartPixel, earliestEndPixel, color, 100, metrics, theme);
       
  8164 
       
  8165     var tapeTrackData = this._getTrackData(tapeTrack);
       
  8166     tapeTrackData.solid = startPixel;
       
  8167 
       
  8168     var labelLeft = latestStartPixel + theme.event.label.offsetFromLine;
       
  8169     var labelTrack = this._findFreeTrackForText(tapeTrack, labelLeft + labelSize.width, function(t) { t.line = latestStartPixel - 2; });
       
  8170     this._getTrackData(labelTrack).text = latestStartPixel - 2;
       
  8171 
       
  8172     this._paintEventLine(evt, latestStartPixel, tapeTrack, labelTrack, metrics, theme);
       
  8173 
       
  8174     var labelTop = Math.round(
       
  8175         metrics.trackOffset + labelTrack * metrics.trackIncrement +
       
  8176         metrics.trackHeight / 2 - labelSize.height / 2);
       
  8177 
       
  8178     var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width, labelSize.height, theme);
       
  8179 
       
  8180     var self = this;
       
  8181     var clickHandler = function(elmt, domEvt, target) {
       
  8182         return self._onClickDurationEvent(tapeElmtData.elmt, domEvt, evt);
       
  8183     };
       
  8184     SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
       
  8185     SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
       
  8186 
       
  8187     this._createHighlightDiv(highlightIndex, tapeElmtData, theme);
       
  8188 
       
  8189     this._eventIdToElmt[evt.getID()] = tapeElmtData.elmt;
       
  8190 };
       
  8191 
       
  8192 Timeline.DetailedEventPainter.prototype._findFreeTrackForSolid = function(solidEdge, softEdge) {
       
  8193     for (var i = 0; true; i++) {
       
  8194         if (i < this._lowerTracks.length) {
       
  8195             var t = this._lowerTracks[i];
       
  8196             if (Math.min(t.solid, t.text) > solidEdge && (!(softEdge) || t.line > softEdge)) {
       
  8197                 return i;
       
  8198             }
       
  8199         } else {
       
  8200             this._lowerTracks.push({
       
  8201                 solid:  Number.POSITIVE_INFINITY,
       
  8202                 text:   Number.POSITIVE_INFINITY,
       
  8203                 line:   Number.POSITIVE_INFINITY
       
  8204             });
       
  8205 
       
  8206             return i;
       
  8207         }
       
  8208 
       
  8209         if (i < this._upperTracks.length) {
       
  8210             var t = this._upperTracks[i];
       
  8211             if (Math.min(t.solid, t.text) > solidEdge && (!(softEdge) || t.line > softEdge)) {
       
  8212                 return -1 - i;
       
  8213             }
       
  8214         } else {
       
  8215             this._upperTracks.push({
       
  8216                 solid:  Number.POSITIVE_INFINITY,
       
  8217                 text:   Number.POSITIVE_INFINITY,
       
  8218                 line:   Number.POSITIVE_INFINITY
       
  8219             });
       
  8220 
       
  8221             return -1 - i;
       
  8222         }
       
  8223     }
       
  8224 };
       
  8225 
       
  8226 Timeline.DetailedEventPainter.prototype._findFreeTrackForText = function(fromTrack, edge, occupiedTrackVisitor) {
       
  8227     var extendUp;
       
  8228     var index;
       
  8229     var firstIndex;
       
  8230     var result;
       
  8231 
       
  8232     if (fromTrack < 0) {
       
  8233         extendUp = true;
       
  8234         firstIndex = -fromTrack;
       
  8235 
       
  8236         index = this._findFreeUpperTrackForText(firstIndex, edge);
       
  8237         result = -1 - index;
       
  8238     } else if (fromTrack > 0) {
       
  8239         extendUp = false;
       
  8240         firstIndex = fromTrack + 1;
       
  8241 
       
  8242         index = this._findFreeLowerTrackForText(firstIndex, edge);
       
  8243         result = index;
       
  8244     } else {
       
  8245         var upIndex = this._findFreeUpperTrackForText(0, edge);
       
  8246         var downIndex = this._findFreeLowerTrackForText(1, edge);
       
  8247 
       
  8248         if (downIndex - 1 <= upIndex) {
       
  8249             extendUp = false;
       
  8250             firstIndex = 1;
       
  8251             index = downIndex;
       
  8252             result = index;
       
  8253         } else {
       
  8254             extendUp = true;
       
  8255             firstIndex = 0;
       
  8256             index = upIndex;
       
  8257             result = -1 - index;
       
  8258         }
       
  8259     }
       
  8260 
       
  8261     if (extendUp) {
       
  8262         if (index == this._upperTracks.length) {
       
  8263             this._upperTracks.push({
       
  8264                 solid:  Number.POSITIVE_INFINITY,
       
  8265                 text:   Number.POSITIVE_INFINITY,
       
  8266                 line:   Number.POSITIVE_INFINITY
       
  8267             });
       
  8268         }
       
  8269         for (var i = firstIndex; i < index; i++) {
       
  8270             occupiedTrackVisitor(this._upperTracks[i]);
       
  8271         }
       
  8272     } else {
       
  8273         if (index == this._lowerTracks.length) {
       
  8274             this._lowerTracks.push({
       
  8275                 solid:  Number.POSITIVE_INFINITY,
       
  8276                 text:   Number.POSITIVE_INFINITY,
       
  8277                 line:   Number.POSITIVE_INFINITY
       
  8278             });
       
  8279         }
       
  8280         for (var i = firstIndex; i < index; i++) {
       
  8281             occupiedTrackVisitor(this._lowerTracks[i]);
       
  8282         }
       
  8283     }
       
  8284     return result;
       
  8285 };
       
  8286 
       
  8287 Timeline.DetailedEventPainter.prototype._findFreeLowerTrackForText = function(index, edge) {
       
  8288     for (; index < this._lowerTracks.length; index++) {
       
  8289         var t = this._lowerTracks[index];
       
  8290         if (Math.min(t.solid, t.text) >= edge) {
       
  8291             break;
       
  8292         }
       
  8293     }
       
  8294     return index;
       
  8295 };
       
  8296 
       
  8297 Timeline.DetailedEventPainter.prototype._findFreeUpperTrackForText = function(index, edge) {
       
  8298     for (; index < this._upperTracks.length; index++) {
       
  8299         var t = this._upperTracks[index];
       
  8300         if (Math.min(t.solid, t.text) >= edge) {
       
  8301             break;
       
  8302         }
       
  8303     }
       
  8304     return index;
       
  8305 };
       
  8306 
       
  8307 Timeline.DetailedEventPainter.prototype._getTrackData = function(index) {
       
  8308     return (index < 0) ? this._upperTracks[-index - 1] : this._lowerTracks[index];
       
  8309 };
       
  8310 
       
  8311 Timeline.DetailedEventPainter.prototype._paintEventLine = function(evt, left, startTrack, endTrack, metrics, theme) {
       
  8312     var top = Math.round(metrics.trackOffset + startTrack * metrics.trackIncrement + metrics.trackHeight / 2);
       
  8313     var height = Math.round(Math.abs(endTrack - startTrack) * metrics.trackIncrement);
       
  8314 
       
  8315     var lineStyle = "1px solid " + theme.event.label.lineColor;
       
  8316     var lineDiv = this._timeline.getDocument().createElement("div");
       
  8317 	lineDiv.style.position = "absolute";
       
  8318     lineDiv.style.left = left + "px";
       
  8319     lineDiv.style.width = theme.event.label.offsetFromLine + "px";
       
  8320     lineDiv.style.height = height + "px";
       
  8321     if (startTrack > endTrack) {
       
  8322         lineDiv.style.top = (top - height) + "px";
       
  8323         lineDiv.style.borderTop = lineStyle;
       
  8324     } else {
       
  8325         lineDiv.style.top = top + "px";
       
  8326         lineDiv.style.borderBottom = lineStyle;
       
  8327     }
       
  8328     lineDiv.style.borderLeft = lineStyle;
       
  8329     this._lineLayer.appendChild(lineDiv);
       
  8330 };
       
  8331 
       
  8332 Timeline.DetailedEventPainter.prototype._paintEventIcon = function(evt, iconTrack, left, metrics, theme) {
       
  8333     var icon = evt.getIcon();
       
  8334     icon = icon != null ? icon : metrics.icon;
       
  8335 
       
  8336     var middle = metrics.trackOffset + iconTrack * metrics.trackIncrement + metrics.trackHeight / 2;
       
  8337     var top = Math.round(middle - metrics.iconHeight / 2);
       
  8338 
       
  8339     var img = SimileAjax.Graphics.createTranslucentImage(icon);
       
  8340     var iconDiv = this._timeline.getDocument().createElement("div");
       
  8341     iconDiv.style.position = "absolute";
       
  8342     iconDiv.style.left = left + "px";
       
  8343     iconDiv.style.top = top + "px";
       
  8344     iconDiv.appendChild(img);
       
  8345     iconDiv.style.cursor = "pointer";
       
  8346 
       
  8347     if(evt._title != null)
       
  8348         iconDiv.title = evt._title
       
  8349 
       
  8350     this._eventLayer.appendChild(iconDiv);
       
  8351 
       
  8352     return {
       
  8353         left:   left,
       
  8354         top:    top,
       
  8355         width:  metrics.iconWidth,
       
  8356         height: metrics.iconHeight,
       
  8357         elmt:   iconDiv
       
  8358     };
       
  8359 };
       
  8360 
       
  8361 Timeline.DetailedEventPainter.prototype._paintEventLabel = function(evt, text, left, top, width, height, theme) {
       
  8362     var doc = this._timeline.getDocument();
       
  8363 
       
  8364     var labelBackgroundDiv = doc.createElement("div");
       
  8365     labelBackgroundDiv.style.position = "absolute";
       
  8366     labelBackgroundDiv.style.left = left + "px";
       
  8367     labelBackgroundDiv.style.width = width + "px";
       
  8368     labelBackgroundDiv.style.top = top + "px";
       
  8369     labelBackgroundDiv.style.height = height + "px";
       
  8370     labelBackgroundDiv.style.backgroundColor = theme.event.label.backgroundColor;
       
  8371     SimileAjax.Graphics.setOpacity(labelBackgroundDiv, theme.event.label.backgroundOpacity);
       
  8372     this._eventLayer.appendChild(labelBackgroundDiv);
       
  8373 
       
  8374     var labelDiv = doc.createElement("div");
       
  8375     labelDiv.style.position = "absolute";
       
  8376     labelDiv.style.left = left + "px";
       
  8377     labelDiv.style.width = width + "px";
       
  8378     labelDiv.style.top = top + "px";
       
  8379     labelDiv.innerHTML = text;
       
  8380     labelDiv.style.cursor = "pointer";
       
  8381 
       
  8382     if(evt._title != null)
       
  8383         labelDiv.title = evt._title;
       
  8384 
       
  8385     var color = evt.getTextColor();
       
  8386     if (color == null) {
       
  8387         color = evt.getColor();
       
  8388     }
       
  8389     if (color != null) {
       
  8390         labelDiv.style.color = color;
       
  8391     }
       
  8392 
       
  8393     this._eventLayer.appendChild(labelDiv);
       
  8394 
       
  8395     return {
       
  8396         left:   left,
       
  8397         top:    top,
       
  8398         width:  width,
       
  8399         height: height,
       
  8400         elmt:   labelDiv
       
  8401     };
       
  8402 };
       
  8403 
       
  8404 Timeline.DetailedEventPainter.prototype._paintEventTape = function(
       
  8405     evt, iconTrack, startPixel, endPixel, color, opacity, metrics, theme) {
       
  8406 
       
  8407     var tapeWidth = endPixel - startPixel;
       
  8408     var tapeHeight = theme.event.tape.height;
       
  8409     var middle = metrics.trackOffset + iconTrack * metrics.trackIncrement + metrics.trackHeight / 2;
       
  8410     var top = Math.round(middle - tapeHeight / 2);
       
  8411 
       
  8412     var tapeDiv = this._timeline.getDocument().createElement("div");
       
  8413     tapeDiv.style.position = "absolute";
       
  8414     tapeDiv.style.left = startPixel + "px";
       
  8415     tapeDiv.style.width = tapeWidth + "px";
       
  8416     tapeDiv.style.top = top + "px";
       
  8417     tapeDiv.style.height = tapeHeight + "px";
       
  8418     tapeDiv.style.backgroundColor = color;
       
  8419     tapeDiv.style.overflow = "hidden";
       
  8420     tapeDiv.style.cursor = "pointer";
       
  8421 
       
  8422     if(evt._title != null)
       
  8423         tapeDiv.title = evt._title;
       
  8424 
       
  8425     SimileAjax.Graphics.setOpacity(tapeDiv, opacity);
       
  8426 
       
  8427     this._eventLayer.appendChild(tapeDiv);
       
  8428 
       
  8429     return {
       
  8430         left:   startPixel,
       
  8431         top:    top,
       
  8432         width:  tapeWidth,
       
  8433         height: tapeHeight,
       
  8434         elmt:   tapeDiv
       
  8435     };
       
  8436 }
       
  8437 
       
  8438 Timeline.DetailedEventPainter.prototype._createHighlightDiv = function(highlightIndex, dimensions, theme) {
       
  8439     if (highlightIndex >= 0) {
       
  8440         var doc = this._timeline.getDocument();
       
  8441         var eventTheme = theme.event;
       
  8442 
       
  8443         var color = eventTheme.highlightColors[Math.min(highlightIndex, eventTheme.highlightColors.length - 1)];
       
  8444 
       
  8445         var div = doc.createElement("div");
       
  8446         div.style.position = "absolute";
       
  8447         div.style.overflow = "hidden";
       
  8448         div.style.left =    (dimensions.left - 2) + "px";
       
  8449         div.style.width =   (dimensions.width + 4) + "px";
       
  8450         div.style.top =     (dimensions.top - 2) + "px";
       
  8451         div.style.height =  (dimensions.height + 4) + "px";
       
  8452         div.style.background = color;
       
  8453 
       
  8454         this._highlightLayer.appendChild(div);
       
  8455     }
       
  8456 };
       
  8457 
       
  8458 Timeline.DetailedEventPainter.prototype._onClickInstantEvent = function(icon, domEvt, evt) {
       
  8459     var c = SimileAjax.DOM.getPageCoordinates(icon);
       
  8460     this._showBubble(
       
  8461         c.left + Math.ceil(icon.offsetWidth / 2),
       
  8462         c.top + Math.ceil(icon.offsetHeight / 2),
       
  8463         evt
       
  8464     );
       
  8465     this._fireOnSelect(evt.getID());
       
  8466 
       
  8467     domEvt.cancelBubble = true;
       
  8468     SimileAjax.DOM.cancelEvent(domEvt);
       
  8469     return false;
       
  8470 };
       
  8471 
       
  8472 Timeline.DetailedEventPainter.prototype._onClickDurationEvent = function(target, domEvt, evt) {
       
  8473     if ("pageX" in domEvt) {
       
  8474         var x = domEvt.pageX;
       
  8475         var y = domEvt.pageY;
       
  8476     } else {
       
  8477         var c = SimileAjax.DOM.getPageCoordinates(target);
       
  8478         var x = domEvt.offsetX + c.left;
       
  8479         var y = domEvt.offsetY + c.top;
       
  8480     }
       
  8481     this._showBubble(x, y, evt);
       
  8482     this._fireOnSelect(evt.getID());
       
  8483 
       
  8484     domEvt.cancelBubble = true;
       
  8485     SimileAjax.DOM.cancelEvent(domEvt);
       
  8486     return false;
       
  8487 };
       
  8488 
       
  8489 Timeline.DetailedEventPainter.prototype.showBubble = function(evt) {
       
  8490     var elmt = this._eventIdToElmt[evt.getID()];
       
  8491     if (elmt) {
       
  8492         var c = SimileAjax.DOM.getPageCoordinates(elmt);
       
  8493         this._showBubble(c.left + elmt.offsetWidth / 2, c.top + elmt.offsetHeight / 2, evt);
       
  8494     }
       
  8495 };
       
  8496 
       
  8497 Timeline.DetailedEventPainter.prototype._showBubble = function(x, y, evt) {
       
  8498     var div = document.createElement("div");
       
  8499     var themeBubble = this._params.theme.event.bubble;
       
  8500     evt.fillInfoBubble(div, this._params.theme, this._band.getLabeller());
       
  8501 
       
  8502     SimileAjax.WindowManager.cancelPopups();
       
  8503     SimileAjax.Graphics.createBubbleForContentAndPoint(div, x, y,
       
  8504        themeBubble.width, null, themeBubble.maxHeight);
       
  8505 };
       
  8506 
       
  8507 Timeline.DetailedEventPainter.prototype._fireOnSelect = function(eventID) {
       
  8508     for (var i = 0; i < this._onSelectListeners.length; i++) {
       
  8509         this._onSelectListeners[i](eventID);
       
  8510     }
       
  8511 };
       
  8512 /*==================================================
       
  8513  *  Overview Event Painter
       
  8514  *==================================================
       
  8515  */
       
  8516 
       
  8517 Timeline.OverviewEventPainter = function(params) {
       
  8518     this._params = params;
       
  8519     this._onSelectListeners = [];
       
  8520 
       
  8521     this._filterMatcher = null;
       
  8522     this._highlightMatcher = null;
       
  8523 };
       
  8524 
       
  8525 Timeline.OverviewEventPainter.prototype.initialize = function(band, timeline) {
       
  8526     this._band = band;
       
  8527     this._timeline = timeline;
       
  8528 
       
  8529     this._eventLayer = null;
       
  8530     this._highlightLayer = null;
       
  8531 };
       
  8532 
       
  8533 Timeline.OverviewEventPainter.prototype.getType = function() {
       
  8534     return 'overview';
       
  8535 };
       
  8536 
       
  8537 Timeline.OverviewEventPainter.prototype.addOnSelectListener = function(listener) {
       
  8538     this._onSelectListeners.push(listener);
       
  8539 };
       
  8540 
       
  8541 Timeline.OverviewEventPainter.prototype.removeOnSelectListener = function(listener) {
       
  8542     for (var i = 0; i < this._onSelectListeners.length; i++) {
       
  8543         if (this._onSelectListeners[i] == listener) {
       
  8544             this._onSelectListeners.splice(i, 1);
       
  8545             break;
       
  8546         }
       
  8547     }
       
  8548 };
       
  8549 
       
  8550 Timeline.OverviewEventPainter.prototype.getFilterMatcher = function() {
       
  8551     return this._filterMatcher;
       
  8552 };
       
  8553 
       
  8554 Timeline.OverviewEventPainter.prototype.setFilterMatcher = function(filterMatcher) {
       
  8555     this._filterMatcher = filterMatcher;
       
  8556 };
       
  8557 
       
  8558 Timeline.OverviewEventPainter.prototype.getHighlightMatcher = function() {
       
  8559     return this._highlightMatcher;
       
  8560 };
       
  8561 
       
  8562 Timeline.OverviewEventPainter.prototype.setHighlightMatcher = function(highlightMatcher) {
       
  8563     this._highlightMatcher = highlightMatcher;
       
  8564 };
       
  8565 
       
  8566 Timeline.OverviewEventPainter.prototype.paint = function() {
       
  8567     var eventSource = this._band.getEventSource();
       
  8568     if (eventSource == null) {
       
  8569         return;
       
  8570     }
       
  8571 
       
  8572     this._prepareForPainting();
       
  8573 
       
  8574     var eventTheme = this._params.theme.event;
       
  8575     var metrics = {
       
  8576         trackOffset:    eventTheme.overviewTrack.offset,
       
  8577         trackHeight:    eventTheme.overviewTrack.height,
       
  8578         trackGap:       eventTheme.overviewTrack.gap,
       
  8579         trackIncrement: eventTheme.overviewTrack.height + eventTheme.overviewTrack.gap
       
  8580     }
       
  8581 
       
  8582     var minDate = this._band.getMinDate();
       
  8583     var maxDate = this._band.getMaxDate();
       
  8584 
       
  8585     var filterMatcher = (this._filterMatcher != null) ?
       
  8586         this._filterMatcher :
       
  8587         function(evt) { return true; };
       
  8588     var highlightMatcher = (this._highlightMatcher != null) ?
       
  8589         this._highlightMatcher :
       
  8590         function(evt) { return -1; };
       
  8591 
       
  8592     var iterator = eventSource.getEventReverseIterator(minDate, maxDate);
       
  8593     while (iterator.hasNext()) {
       
  8594         var evt = iterator.next();
       
  8595         if (filterMatcher(evt)) {
       
  8596             this.paintEvent(evt, metrics, this._params.theme, highlightMatcher(evt));
       
  8597         }
       
  8598     }
       
  8599 
       
  8600     this._highlightLayer.style.display = "block";
       
  8601     this._eventLayer.style.display = "block";
       
  8602     // update the band object for max number of tracks in this section of the ether
       
  8603     this._band.updateEventTrackInfo(this._tracks.length, metrics.trackIncrement);
       
  8604 };
       
  8605 
       
  8606 Timeline.OverviewEventPainter.prototype.softPaint = function() {
       
  8607 };
       
  8608 
       
  8609 Timeline.OverviewEventPainter.prototype._prepareForPainting = function() {
       
  8610     var band = this._band;
       
  8611 
       
  8612     this._tracks = [];
       
  8613 
       
  8614     if (this._highlightLayer != null) {
       
  8615         band.removeLayerDiv(this._highlightLayer);
       
  8616     }
       
  8617     this._highlightLayer = band.createLayerDiv(105, "timeline-band-highlights");
       
  8618     this._highlightLayer.style.display = "none";
       
  8619 
       
  8620     if (this._eventLayer != null) {
       
  8621         band.removeLayerDiv(this._eventLayer);
       
  8622     }
       
  8623     this._eventLayer = band.createLayerDiv(110, "timeline-band-events");
       
  8624     this._eventLayer.style.display = "none";
       
  8625 };
       
  8626 
       
  8627 Timeline.OverviewEventPainter.prototype.paintEvent = function(evt, metrics, theme, highlightIndex) {
       
  8628     if (evt.isInstant()) {
       
  8629         this.paintInstantEvent(evt, metrics, theme, highlightIndex);
       
  8630     } else {
       
  8631         this.paintDurationEvent(evt, metrics, theme, highlightIndex);
       
  8632     }
       
  8633 };
       
  8634 
       
  8635 Timeline.OverviewEventPainter.prototype.paintInstantEvent = function(evt, metrics, theme, highlightIndex) {
       
  8636     var startDate = evt.getStart();
       
  8637     var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
       
  8638 
       
  8639     var color = evt.getColor(),
       
  8640         klassName = evt.getClassName();
       
  8641     if (klassName) {
       
  8642       color = null;
       
  8643     } else {
       
  8644       color = color != null ? color : theme.event.duration.color;
       
  8645     }
       
  8646 
       
  8647     var tickElmtData = this._paintEventTick(evt, startPixel, color, 100, metrics, theme);
       
  8648 
       
  8649     this._createHighlightDiv(highlightIndex, tickElmtData, theme);
       
  8650 };
       
  8651 
       
  8652 Timeline.OverviewEventPainter.prototype.paintDurationEvent = function(evt, metrics, theme, highlightIndex) {
       
  8653     var latestStartDate = evt.getLatestStart();
       
  8654     var earliestEndDate = evt.getEarliestEnd();
       
  8655 
       
  8656     var latestStartPixel = Math.round(this._band.dateToPixelOffset(latestStartDate));
       
  8657     var earliestEndPixel = Math.round(this._band.dateToPixelOffset(earliestEndDate));
       
  8658 
       
  8659     var tapeTrack = 0;
       
  8660     for (; tapeTrack < this._tracks.length; tapeTrack++) {
       
  8661         if (earliestEndPixel < this._tracks[tapeTrack]) {
       
  8662             break;
       
  8663         }
       
  8664     }
       
  8665     this._tracks[tapeTrack] = earliestEndPixel;
       
  8666 
       
  8667     var color = evt.getColor(),
       
  8668         klassName = evt.getClassName();
       
  8669     if (klassName) {
       
  8670       color = null;
       
  8671     } else {
       
  8672       color = color != null ? color : theme.event.duration.color;
       
  8673     }
       
  8674 
       
  8675     var tapeElmtData = this._paintEventTape(evt, tapeTrack, latestStartPixel, earliestEndPixel,
       
  8676       color, 100, metrics, theme, klassName);
       
  8677 
       
  8678     this._createHighlightDiv(highlightIndex, tapeElmtData, theme);
       
  8679 };
       
  8680 
       
  8681 Timeline.OverviewEventPainter.prototype._paintEventTape = function(
       
  8682     evt, track, left, right, color, opacity, metrics, theme, klassName) {
       
  8683 
       
  8684     var top = metrics.trackOffset + track * metrics.trackIncrement;
       
  8685     var width = right - left;
       
  8686     var height = metrics.trackHeight;
       
  8687 
       
  8688     var tapeDiv = this._timeline.getDocument().createElement("div");
       
  8689     tapeDiv.className = 'timeline-small-event-tape'
       
  8690     if (klassName) {tapeDiv.className += ' small-' + klassName;}
       
  8691     tapeDiv.style.left = left + "px";
       
  8692     tapeDiv.style.width = width + "px";
       
  8693     tapeDiv.style.top = top + "px";
       
  8694     tapeDiv.style.height = height + "px";
       
  8695 
       
  8696     if (color) {
       
  8697       tapeDiv.style.backgroundColor = color; // set color here if defined by event. Else use css
       
  8698     }
       
  8699  //   tapeDiv.style.overflow = "hidden";   // now set in css
       
  8700  //   tapeDiv.style.position = "absolute";
       
  8701     if(opacity<100) SimileAjax.Graphics.setOpacity(tapeDiv, opacity);
       
  8702 
       
  8703     this._eventLayer.appendChild(tapeDiv);
       
  8704 
       
  8705     return {
       
  8706         left:   left,
       
  8707         top:    top,
       
  8708         width:  width,
       
  8709         height: height,
       
  8710         elmt:   tapeDiv
       
  8711     };
       
  8712 }
       
  8713 
       
  8714 Timeline.OverviewEventPainter.prototype._paintEventTick = function(
       
  8715     evt, left, color, opacity, metrics, theme) {
       
  8716 
       
  8717     var height = theme.event.overviewTrack.tickHeight;
       
  8718     var top = metrics.trackOffset - height;
       
  8719     var width = 1;
       
  8720 
       
  8721     var tickDiv = this._timeline.getDocument().createElement("div");
       
  8722 	  tickDiv.className = 'timeline-small-event-icon'
       
  8723     tickDiv.style.left = left + "px";
       
  8724     tickDiv.style.top = top + "px";
       
  8725   //  tickDiv.style.width = width + "px";
       
  8726   //  tickDiv.style.position = "absolute";
       
  8727   //  tickDiv.style.height = height + "px";
       
  8728   //  tickDiv.style.backgroundColor = color;
       
  8729   //  tickDiv.style.overflow = "hidden";
       
  8730 
       
  8731     var klassName = evt.getClassName()
       
  8732     if (klassName) {tickDiv.className +=' small-' + klassName};
       
  8733 
       
  8734     if(opacity<100) {SimileAjax.Graphics.setOpacity(tickDiv, opacity)};
       
  8735 
       
  8736     this._eventLayer.appendChild(tickDiv);
       
  8737 
       
  8738     return {
       
  8739         left:   left,
       
  8740         top:    top,
       
  8741         width:  width,
       
  8742         height: height,
       
  8743         elmt:   tickDiv
       
  8744     };
       
  8745 }
       
  8746 
       
  8747 Timeline.OverviewEventPainter.prototype._createHighlightDiv = function(highlightIndex, dimensions, theme) {
       
  8748     if (highlightIndex >= 0) {
       
  8749         var doc = this._timeline.getDocument();
       
  8750         var eventTheme = theme.event;
       
  8751 
       
  8752         var color = eventTheme.highlightColors[Math.min(highlightIndex, eventTheme.highlightColors.length - 1)];
       
  8753 
       
  8754         var div = doc.createElement("div");
       
  8755         div.style.position = "absolute";
       
  8756         div.style.overflow = "hidden";
       
  8757         div.style.left =    (dimensions.left - 1) + "px";
       
  8758         div.style.width =   (dimensions.width + 2) + "px";
       
  8759         div.style.top =     (dimensions.top - 1) + "px";
       
  8760         div.style.height =  (dimensions.height + 2) + "px";
       
  8761         div.style.background = color;
       
  8762 
       
  8763         this._highlightLayer.appendChild(div);
       
  8764     }
       
  8765 };
       
  8766 
       
  8767 Timeline.OverviewEventPainter.prototype.showBubble = function(evt) {
       
  8768     // not implemented
       
  8769 };
       
  8770 /*==================================================
       
  8771  *  Compact Event Painter
       
  8772  *==================================================
       
  8773  */
       
  8774 
       
  8775 Timeline.CompactEventPainter = function(params) {
       
  8776     this._params = params;
       
  8777     this._onSelectListeners = [];
       
  8778 
       
  8779     this._filterMatcher = null;
       
  8780     this._highlightMatcher = null;
       
  8781     this._frc = null;
       
  8782 
       
  8783     this._eventIdToElmt = {};
       
  8784 };
       
  8785 
       
  8786 Timeline.CompactEventPainter.prototype.getType = function() {
       
  8787     return 'compact';
       
  8788 };
       
  8789 
       
  8790 Timeline.CompactEventPainter.prototype.initialize = function(band, timeline) {
       
  8791     this._band = band;
       
  8792     this._timeline = timeline;
       
  8793 
       
  8794     this._backLayer = null;
       
  8795     this._eventLayer = null;
       
  8796     this._lineLayer = null;
       
  8797     this._highlightLayer = null;
       
  8798 
       
  8799     this._eventIdToElmt = null;
       
  8800 };
       
  8801 
       
  8802 Timeline.CompactEventPainter.prototype.addOnSelectListener = function(listener) {
       
  8803     this._onSelectListeners.push(listener);
       
  8804 };
       
  8805 
       
  8806 Timeline.CompactEventPainter.prototype.removeOnSelectListener = function(listener) {
       
  8807     for (var i = 0; i < this._onSelectListeners.length; i++) {
       
  8808         if (this._onSelectListeners[i] == listener) {
       
  8809             this._onSelectListeners.splice(i, 1);
       
  8810             break;
       
  8811         }
       
  8812     }
       
  8813 };
       
  8814 
       
  8815 Timeline.CompactEventPainter.prototype.getFilterMatcher = function() {
       
  8816     return this._filterMatcher;
       
  8817 };
       
  8818 
       
  8819 Timeline.CompactEventPainter.prototype.setFilterMatcher = function(filterMatcher) {
       
  8820     this._filterMatcher = filterMatcher;
       
  8821 };
       
  8822 
       
  8823 Timeline.CompactEventPainter.prototype.getHighlightMatcher = function() {
       
  8824     return this._highlightMatcher;
       
  8825 };
       
  8826 
       
  8827 Timeline.CompactEventPainter.prototype.setHighlightMatcher = function(highlightMatcher) {
       
  8828     this._highlightMatcher = highlightMatcher;
       
  8829 };
       
  8830 
       
  8831 Timeline.CompactEventPainter.prototype.paint = function() {
       
  8832     var eventSource = this._band.getEventSource();
       
  8833     if (eventSource == null) {
       
  8834         return;
       
  8835     }
       
  8836 
       
  8837     this._eventIdToElmt = {};
       
  8838     this._prepareForPainting();
       
  8839 
       
  8840     var metrics = this._computeMetrics();
       
  8841     var minDate = this._band.getMinDate();
       
  8842     var maxDate = this._band.getMaxDate();
       
  8843 
       
  8844     var filterMatcher = (this._filterMatcher != null) ?
       
  8845         this._filterMatcher :
       
  8846         function(evt) { return true; };
       
  8847 
       
  8848     var highlightMatcher = (this._highlightMatcher != null) ?
       
  8849         this._highlightMatcher :
       
  8850         function(evt) { return -1; };
       
  8851 
       
  8852     var iterator = eventSource.getEventIterator(minDate, maxDate);
       
  8853 
       
  8854     var stackConcurrentPreciseInstantEvents = "stackConcurrentPreciseInstantEvents" in this._params && typeof this._params.stackConcurrentPreciseInstantEvents == "object";
       
  8855     var collapseConcurrentPreciseInstantEvents = "collapseConcurrentPreciseInstantEvents" in this._params && this._params.collapseConcurrentPreciseInstantEvents;
       
  8856     if (collapseConcurrentPreciseInstantEvents || stackConcurrentPreciseInstantEvents) {
       
  8857         var bufferedEvents = [];
       
  8858         var previousInstantEvent = null;
       
  8859 
       
  8860         while (iterator.hasNext()) {
       
  8861             var evt = iterator.next();
       
  8862             if (filterMatcher(evt)) {
       
  8863                 if (!evt.isInstant() || evt.isImprecise()) {
       
  8864                     this.paintEvent(evt, metrics, this._params.theme, highlightMatcher(evt));
       
  8865                 } else if (previousInstantEvent != null &&
       
  8866                         previousInstantEvent.getStart().getTime() == evt.getStart().getTime()) {
       
  8867                     bufferedEvents[bufferedEvents.length - 1].push(evt);
       
  8868                 } else {
       
  8869                     bufferedEvents.push([ evt ]);
       
  8870                     previousInstantEvent = evt;
       
  8871                 }
       
  8872             }
       
  8873         }
       
  8874 
       
  8875         for (var i = 0; i < bufferedEvents.length; i++) {
       
  8876             var compositeEvents = bufferedEvents[i];
       
  8877             if (compositeEvents.length == 1) {
       
  8878                 this.paintEvent(compositeEvents[0], metrics, this._params.theme, highlightMatcher(evt));
       
  8879             } else {
       
  8880                 var match = -1;
       
  8881                 for (var j = 0; match < 0 && j < compositeEvents.length; j++) {
       
  8882                     match = highlightMatcher(compositeEvents[j]);
       
  8883                 }
       
  8884 
       
  8885                 if (stackConcurrentPreciseInstantEvents) {
       
  8886                     this.paintStackedPreciseInstantEvents(compositeEvents, metrics, this._params.theme, match);
       
  8887                 } else {
       
  8888                     this.paintCompositePreciseInstantEvents(compositeEvents, metrics, this._params.theme, match);
       
  8889                 }
       
  8890             }
       
  8891         }
       
  8892     } else {
       
  8893         while (iterator.hasNext()) {
       
  8894             var evt = iterator.next();
       
  8895             if (filterMatcher(evt)) {
       
  8896                 this.paintEvent(evt, metrics, this._params.theme, highlightMatcher(evt));
       
  8897             }
       
  8898         }
       
  8899     }
       
  8900 
       
  8901     this._highlightLayer.style.display = "block";
       
  8902     this._lineLayer.style.display = "block";
       
  8903     this._eventLayer.style.display = "block";
       
  8904 
       
  8905     this._setOrthogonalOffset(metrics);
       
  8906 };
       
  8907 
       
  8908 Timeline.CompactEventPainter.prototype.softPaint = function() {
       
  8909     this._setOrthogonalOffset(this._computeMetrics());
       
  8910 };
       
  8911 
       
  8912 Timeline.CompactEventPainter.prototype._setOrthogonalOffset = function(metrics) {
       
  8913     var actualViewWidth = 2 * metrics.trackOffset + this._tracks.length * metrics.trackHeight;
       
  8914     var minOrthogonalOffset = Math.min(0, this._band.getViewWidth() - actualViewWidth);
       
  8915     var orthogonalOffset = Math.max(minOrthogonalOffset, this._band.getViewOrthogonalOffset());
       
  8916 
       
  8917     this._highlightLayer.style.top =
       
  8918         this._lineLayer.style.top =
       
  8919             this._eventLayer.style.top =
       
  8920                 orthogonalOffset + "px";
       
  8921 };
       
  8922 
       
  8923 Timeline.CompactEventPainter.prototype._computeMetrics = function() {
       
  8924     var theme = this._params.theme;
       
  8925     var eventTheme = theme.event;
       
  8926 
       
  8927     var metrics = {
       
  8928         trackOffset:            "trackOffset" in this._params ? this._params.trackOffset : 10,
       
  8929         trackHeight:            "trackHeight" in this._params ? this._params.trackHeight : 10,
       
  8930 
       
  8931         tapeHeight:             theme.event.tape.height,
       
  8932         tapeBottomMargin:       "tapeBottomMargin" in this._params ? this._params.tapeBottomMargin : 2,
       
  8933 
       
  8934         labelBottomMargin:      "labelBottomMargin" in this._params ? this._params.labelBottomMargin : 5,
       
  8935         labelRightMargin:       "labelRightMargin" in this._params ? this._params.labelRightMargin : 5,
       
  8936 
       
  8937         defaultIcon:            eventTheme.instant.icon,
       
  8938         defaultIconWidth:       eventTheme.instant.iconWidth,
       
  8939         defaultIconHeight:      eventTheme.instant.iconHeight,
       
  8940 
       
  8941         customIconWidth:        "iconWidth" in this._params ? this._params.iconWidth : eventTheme.instant.iconWidth,
       
  8942         customIconHeight:       "iconHeight" in this._params ? this._params.iconHeight : eventTheme.instant.iconHeight,
       
  8943 
       
  8944         iconLabelGap:           "iconLabelGap" in this._params ? this._params.iconLabelGap : 2,
       
  8945         iconBottomMargin:       "iconBottomMargin" in this._params ? this._params.iconBottomMargin : 2
       
  8946     };
       
  8947     if ("compositeIcon" in this._params) {
       
  8948         metrics.compositeIcon = this._params.compositeIcon;
       
  8949         metrics.compositeIconWidth = this._params.compositeIconWidth || metrics.customIconWidth;
       
  8950         metrics.compositeIconHeight = this._params.compositeIconHeight || metrics.customIconHeight;
       
  8951     } else {
       
  8952         metrics.compositeIcon = metrics.defaultIcon;
       
  8953         metrics.compositeIconWidth = metrics.defaultIconWidth;
       
  8954         metrics.compositeIconHeight = metrics.defaultIconHeight;
       
  8955     }
       
  8956     metrics.defaultStackIcon = "icon" in this._params.stackConcurrentPreciseInstantEvents ?
       
  8957         this._params.stackConcurrentPreciseInstantEvents.icon : metrics.defaultIcon;
       
  8958     metrics.defaultStackIconWidth = "iconWidth" in this._params.stackConcurrentPreciseInstantEvents ?
       
  8959         this._params.stackConcurrentPreciseInstantEvents.iconWidth : metrics.defaultIconWidth;
       
  8960     metrics.defaultStackIconHeight = "iconHeight" in this._params.stackConcurrentPreciseInstantEvents ?
       
  8961         this._params.stackConcurrentPreciseInstantEvents.iconHeight : metrics.defaultIconHeight;
       
  8962 
       
  8963     return metrics;
       
  8964 };
       
  8965 
       
  8966 Timeline.CompactEventPainter.prototype._prepareForPainting = function() {
       
  8967     var band = this._band;
       
  8968 
       
  8969     if (this._backLayer == null) {
       
  8970         this._backLayer = this._band.createLayerDiv(0, "timeline-band-events");
       
  8971         this._backLayer.style.visibility = "hidden";
       
  8972 
       
  8973         var eventLabelPrototype = document.createElement("span");
       
  8974         eventLabelPrototype.className = "timeline-event-label";
       
  8975         this._backLayer.appendChild(eventLabelPrototype);
       
  8976         this._frc = SimileAjax.Graphics.getFontRenderingContext(eventLabelPrototype);
       
  8977     }
       
  8978     this._frc.update();
       
  8979     this._tracks = [];
       
  8980 
       
  8981     if (this._highlightLayer != null) {
       
  8982         band.removeLayerDiv(this._highlightLayer);
       
  8983     }
       
  8984     this._highlightLayer = band.createLayerDiv(105, "timeline-band-highlights");
       
  8985     this._highlightLayer.style.display = "none";
       
  8986 
       
  8987     if (this._lineLayer != null) {
       
  8988         band.removeLayerDiv(this._lineLayer);
       
  8989     }
       
  8990     this._lineLayer = band.createLayerDiv(110, "timeline-band-lines");
       
  8991     this._lineLayer.style.display = "none";
       
  8992 
       
  8993     if (this._eventLayer != null) {
       
  8994         band.removeLayerDiv(this._eventLayer);
       
  8995     }
       
  8996     this._eventLayer = band.createLayerDiv(115, "timeline-band-events");
       
  8997     this._eventLayer.style.display = "none";
       
  8998 };
       
  8999 
       
  9000 Timeline.CompactEventPainter.prototype.paintEvent = function(evt, metrics, theme, highlightIndex) {
       
  9001     if (evt.isInstant()) {
       
  9002         this.paintInstantEvent(evt, metrics, theme, highlightIndex);
       
  9003     } else {
       
  9004         this.paintDurationEvent(evt, metrics, theme, highlightIndex);
       
  9005     }
       
  9006 };
       
  9007 
       
  9008 Timeline.CompactEventPainter.prototype.paintInstantEvent = function(evt, metrics, theme, highlightIndex) {
       
  9009     if (evt.isImprecise()) {
       
  9010         this.paintImpreciseInstantEvent(evt, metrics, theme, highlightIndex);
       
  9011     } else {
       
  9012         this.paintPreciseInstantEvent(evt, metrics, theme, highlightIndex);
       
  9013     }
       
  9014 }
       
  9015 
       
  9016 Timeline.CompactEventPainter.prototype.paintDurationEvent = function(evt, metrics, theme, highlightIndex) {
       
  9017     if (evt.isImprecise()) {
       
  9018         this.paintImpreciseDurationEvent(evt, metrics, theme, highlightIndex);
       
  9019     } else {
       
  9020         this.paintPreciseDurationEvent(evt, metrics, theme, highlightIndex);
       
  9021     }
       
  9022 }
       
  9023 
       
  9024 Timeline.CompactEventPainter.prototype.paintPreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
       
  9025     var commonData = {
       
  9026         tooltip: evt.getProperty("tooltip") || evt.getText()
       
  9027     };
       
  9028 
       
  9029     var iconData = {
       
  9030         url: evt.getIcon()
       
  9031     };
       
  9032     if (iconData.url == null) {
       
  9033         iconData.url = metrics.defaultIcon;
       
  9034         iconData.width = metrics.defaultIconWidth;
       
  9035         iconData.height = metrics.defaultIconHeight;
       
  9036         iconData.className = "timeline-event-icon-default";
       
  9037     } else {
       
  9038         iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth;
       
  9039         iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight;
       
  9040     }
       
  9041 
       
  9042     var labelData = {
       
  9043         text:       evt.getText(),
       
  9044         color:      evt.getTextColor() || evt.getColor(),
       
  9045         className:  evt.getClassName()
       
  9046     };
       
  9047 
       
  9048     var result = this.paintTapeIconLabel(
       
  9049         evt.getStart(),
       
  9050         commonData,
       
  9051         null, // no tape data
       
  9052         iconData,
       
  9053         labelData,
       
  9054         metrics,
       
  9055         theme,
       
  9056         highlightIndex
       
  9057     );
       
  9058 
       
  9059     var self = this;
       
  9060     var clickHandler = function(elmt, domEvt, target) {
       
  9061         return self._onClickInstantEvent(result.iconElmtData.elmt, domEvt, evt);
       
  9062     };
       
  9063     SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler);
       
  9064     SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler);
       
  9065 
       
  9066     this._eventIdToElmt[evt.getID()] = result.iconElmtData.elmt;
       
  9067 };
       
  9068 
       
  9069 Timeline.CompactEventPainter.prototype.paintCompositePreciseInstantEvents = function(events, metrics, theme, highlightIndex) {
       
  9070     var evt = events[0];
       
  9071 
       
  9072     var tooltips = [];
       
  9073     for (var i = 0; i < events.length; i++) {
       
  9074         tooltips.push(events[i].getProperty("tooltip") || events[i].getText());
       
  9075     }
       
  9076     var commonData = {
       
  9077         tooltip: tooltips.join("; ")
       
  9078     };
       
  9079 
       
  9080     var iconData = {
       
  9081         url: metrics.compositeIcon,
       
  9082         width: metrics.compositeIconWidth,
       
  9083         height: metrics.compositeIconHeight,
       
  9084         className: "timeline-event-icon-composite"
       
  9085     };
       
  9086 
       
  9087     var labelData = {
       
  9088         text: String.substitute(this._params.compositeEventLabelTemplate, [ events.length ])
       
  9089     };
       
  9090 
       
  9091     var result = this.paintTapeIconLabel(
       
  9092         evt.getStart(),
       
  9093         commonData,
       
  9094         null, // no tape data
       
  9095         iconData,
       
  9096         labelData,
       
  9097         metrics,
       
  9098         theme,
       
  9099         highlightIndex
       
  9100     );
       
  9101 
       
  9102     var self = this;
       
  9103     var clickHandler = function(elmt, domEvt, target) {
       
  9104         return self._onClickMultiplePreciseInstantEvent(result.iconElmtData.elmt, domEvt, events);
       
  9105     };
       
  9106 
       
  9107     SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler);
       
  9108     SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler);
       
  9109 
       
  9110     for (var i = 0; i < events.length; i++) {
       
  9111         this._eventIdToElmt[events[i].getID()] = result.iconElmtData.elmt;
       
  9112     }
       
  9113 };
       
  9114 
       
  9115 Timeline.CompactEventPainter.prototype.paintStackedPreciseInstantEvents = function(events, metrics, theme, highlightIndex) {
       
  9116     var limit = "limit" in this._params.stackConcurrentPreciseInstantEvents ?
       
  9117         this._params.stackConcurrentPreciseInstantEvents.limit : 10;
       
  9118     var moreMessageTemplate = "moreMessageTemplate" in this._params.stackConcurrentPreciseInstantEvents ?
       
  9119         this._params.stackConcurrentPreciseInstantEvents.moreMessageTemplate : "%0 More Events";
       
  9120     var showMoreMessage = limit <= events.length - 2; // We want at least 2 more events above the limit.
       
  9121                                                       // Otherwise we'd need the singular case of "1 More Event"
       
  9122 
       
  9123     var band = this._band;
       
  9124     var getPixelOffset = function(date) {
       
  9125         return Math.round(band.dateToPixelOffset(date));
       
  9126     };
       
  9127     var getIconData = function(evt) {
       
  9128         var iconData = {
       
  9129             url: evt.getIcon()
       
  9130         };
       
  9131         if (iconData.url == null) {
       
  9132             iconData.url = metrics.defaultStackIcon;
       
  9133             iconData.width = metrics.defaultStackIconWidth;
       
  9134             iconData.height = metrics.defaultStackIconHeight;
       
  9135             iconData.className = "timeline-event-icon-stack timeline-event-icon-default";
       
  9136         } else {
       
  9137             iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth;
       
  9138             iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight;
       
  9139             iconData.className = "timeline-event-icon-stack";
       
  9140         }
       
  9141         return iconData;
       
  9142     };
       
  9143 
       
  9144     var firstIconData = getIconData(events[0]);
       
  9145     var horizontalIncrement = 5;
       
  9146     var leftIconEdge = 0;
       
  9147     var totalLabelWidth = 0;
       
  9148     var totalLabelHeight = 0;
       
  9149     var totalIconHeight = 0;
       
  9150 
       
  9151     var records = [];
       
  9152     for (var i = 0; i < events.length && (!showMoreMessage || i < limit); i++) {
       
  9153         var evt = events[i];
       
  9154         var text = evt.getText();
       
  9155         var iconData = getIconData(evt);
       
  9156         var labelSize = this._frc.computeSize(text);
       
  9157         var record = {
       
  9158             text:       text,
       
  9159             iconData:   iconData,
       
  9160             labelSize:  labelSize,
       
  9161             iconLeft:   firstIconData.width + i * horizontalIncrement - iconData.width
       
  9162         };
       
  9163         record.labelLeft = firstIconData.width + i * horizontalIncrement + metrics.iconLabelGap;
       
  9164         record.top = totalLabelHeight;
       
  9165         records.push(record);
       
  9166 
       
  9167         leftIconEdge = Math.min(leftIconEdge, record.iconLeft);
       
  9168         totalLabelHeight += labelSize.height;
       
  9169         totalLabelWidth = Math.max(totalLabelWidth, record.labelLeft + labelSize.width);
       
  9170         totalIconHeight = Math.max(totalIconHeight, record.top + iconData.height);
       
  9171     }
       
  9172     if (showMoreMessage) {
       
  9173         var moreMessage = String.substitute(moreMessageTemplate, [ events.length - limit ]);
       
  9174 
       
  9175         var moreMessageLabelSize = this._frc.computeSize(moreMessage);
       
  9176         var moreMessageLabelLeft = firstIconData.width + (limit - 1) * horizontalIncrement + metrics.iconLabelGap;
       
  9177         var moreMessageLabelTop = totalLabelHeight;
       
  9178 
       
  9179         totalLabelHeight += moreMessageLabelSize.height;
       
  9180         totalLabelWidth = Math.max(totalLabelWidth, moreMessageLabelLeft + moreMessageLabelSize.width);
       
  9181     }
       
  9182     totalLabelWidth += metrics.labelRightMargin;
       
  9183     totalLabelHeight += metrics.labelBottomMargin;
       
  9184     totalIconHeight += metrics.iconBottomMargin;
       
  9185 
       
  9186     var anchorPixel = getPixelOffset(events[0].getStart());
       
  9187     var newTracks = [];
       
  9188 
       
  9189     var trackCount = Math.ceil(Math.max(totalIconHeight, totalLabelHeight) / metrics.trackHeight);
       
  9190     var rightIconEdge = firstIconData.width + (events.length - 1) * horizontalIncrement;
       
  9191     for (var i = 0; i < trackCount; i++) {
       
  9192         newTracks.push({ start: leftIconEdge, end: rightIconEdge });
       
  9193     }
       
  9194     var labelTrackCount = Math.ceil(totalLabelHeight / metrics.trackHeight);
       
  9195     for (var i = 0; i < labelTrackCount; i++) {
       
  9196         var track = newTracks[i];
       
  9197         track.end = Math.max(track.end, totalLabelWidth);
       
  9198     }
       
  9199 
       
  9200     var firstTrack = this._fitTracks(anchorPixel, newTracks);
       
  9201     var verticalPixelOffset = firstTrack * metrics.trackHeight + metrics.trackOffset;
       
  9202 
       
  9203     var iconStackDiv = this._timeline.getDocument().createElement("div");
       
  9204     iconStackDiv.className = 'timeline-event-icon-stack';
       
  9205     iconStackDiv.style.position = "absolute";
       
  9206     iconStackDiv.style.overflow = "visible";
       
  9207     iconStackDiv.style.left = anchorPixel + "px";
       
  9208     iconStackDiv.style.top = verticalPixelOffset + "px";
       
  9209     iconStackDiv.style.width = rightIconEdge + "px";
       
  9210     iconStackDiv.style.height = totalIconHeight + "px";
       
  9211     iconStackDiv.innerHTML = "<div style='position: relative'></div>";
       
  9212     this._eventLayer.appendChild(iconStackDiv);
       
  9213 
       
  9214     var self = this;
       
  9215     var onMouseOver = function(domEvt) {
       
  9216         try {
       
  9217             var n = parseInt(this.getAttribute("index"));
       
  9218             var childNodes = iconStackDiv.firstChild.childNodes;
       
  9219             for (var i = 0; i < childNodes.length; i++) {
       
  9220                 var child = childNodes[i];
       
  9221                 if (i == n) {
       
  9222                     child.style.zIndex = childNodes.length;
       
  9223                 } else {
       
  9224                     child.style.zIndex = childNodes.length - i;
       
  9225                 }
       
  9226             }
       
  9227         } catch (e) {
       
  9228         }
       
  9229     };
       
  9230     var paintEvent = function(index) {
       
  9231         var record = records[index];
       
  9232         var evt = events[index];
       
  9233         var tooltip = evt.getProperty("tooltip") || evt.getText();
       
  9234 
       
  9235         var labelElmtData = self._paintEventLabel(
       
  9236             { tooltip: tooltip },
       
  9237             { text: record.text },
       
  9238             anchorPixel + record.labelLeft,
       
  9239             verticalPixelOffset + record.top,
       
  9240             record.labelSize.width,
       
  9241             record.labelSize.height,
       
  9242             theme
       
  9243         );
       
  9244         labelElmtData.elmt.setAttribute("index", index);
       
  9245         labelElmtData.elmt.onmouseover = onMouseOver;
       
  9246 
       
  9247         var img = SimileAjax.Graphics.createTranslucentImage(record.iconData.url);
       
  9248         var iconDiv = self._timeline.getDocument().createElement("div");
       
  9249         iconDiv.className = 'timeline-event-icon' + ("className" in record.iconData ? (" " + record.iconData.className) : "");
       
  9250         iconDiv.style.left = record.iconLeft + "px";
       
  9251         iconDiv.style.top = record.top + "px";
       
  9252         iconDiv.style.zIndex = (records.length - index);
       
  9253         iconDiv.appendChild(img);
       
  9254         iconDiv.setAttribute("index", index);
       
  9255         iconDiv.onmouseover = onMouseOver;
       
  9256 
       
  9257         iconStackDiv.firstChild.appendChild(iconDiv);
       
  9258 
       
  9259         var clickHandler = function(elmt, domEvt, target) {
       
  9260             return self._onClickInstantEvent(labelElmtData.elmt, domEvt, evt);
       
  9261         };
       
  9262 
       
  9263         SimileAjax.DOM.registerEvent(iconDiv, "mousedown", clickHandler);
       
  9264         SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
       
  9265 
       
  9266         self._eventIdToElmt[evt.getID()] = iconDiv;
       
  9267     };
       
  9268     for (var i = 0; i < records.length; i++) {
       
  9269         paintEvent(i);
       
  9270     }
       
  9271 
       
  9272     if (showMoreMessage) {
       
  9273         var moreEvents = events.slice(limit);
       
  9274         var moreMessageLabelElmtData = this._paintEventLabel(
       
  9275             { tooltip: moreMessage },
       
  9276             { text: moreMessage },
       
  9277             anchorPixel + moreMessageLabelLeft,
       
  9278             verticalPixelOffset + moreMessageLabelTop,
       
  9279             moreMessageLabelSize.width,
       
  9280             moreMessageLabelSize.height,
       
  9281             theme
       
  9282         );
       
  9283 
       
  9284         var moreMessageClickHandler = function(elmt, domEvt, target) {
       
  9285             return self._onClickMultiplePreciseInstantEvent(moreMessageLabelElmtData.elmt, domEvt, moreEvents);
       
  9286         };
       
  9287         SimileAjax.DOM.registerEvent(moreMessageLabelElmtData.elmt, "mousedown", moreMessageClickHandler);
       
  9288 
       
  9289         for (var i = 0; i < moreEvents.length; i++) {
       
  9290             this._eventIdToElmt[moreEvents[i].getID()] = moreMessageLabelElmtData.elmt;
       
  9291         }
       
  9292     }
       
  9293     //this._createHighlightDiv(highlightIndex, iconElmtData, theme);
       
  9294 };
       
  9295 
       
  9296 Timeline.CompactEventPainter.prototype.paintImpreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
       
  9297     var commonData = {
       
  9298         tooltip: evt.getProperty("tooltip") || evt.getText()
       
  9299     };
       
  9300 
       
  9301     var tapeData = {
       
  9302         start:          evt.getStart(),
       
  9303         end:            evt.getEnd(),
       
  9304         latestStart:    evt.getLatestStart(),
       
  9305         earliestEnd:    evt.getEarliestEnd(),
       
  9306         isInstant:      true
       
  9307     };
       
  9308 
       
  9309     var iconData = {
       
  9310         url: evt.getIcon()
       
  9311     };
       
  9312     if (iconData.url == null) {
       
  9313         iconData = null;
       
  9314     } else {
       
  9315         iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth;
       
  9316         iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight;
       
  9317     }
       
  9318 
       
  9319     var labelData = {
       
  9320         text:       evt.getText(),
       
  9321         color:      evt.getTextColor() || evt.getColor(),
       
  9322         className:  evt.getClassName()
       
  9323     };
       
  9324 
       
  9325     var result = this.paintTapeIconLabel(
       
  9326         evt.getStart(),
       
  9327         commonData,
       
  9328         tapeData, // no tape data
       
  9329         iconData,
       
  9330         labelData,
       
  9331         metrics,
       
  9332         theme,
       
  9333         highlightIndex
       
  9334     );
       
  9335 
       
  9336     var self = this;
       
  9337     var clickHandler = iconData != null ?
       
  9338         function(elmt, domEvt, target) {
       
  9339             return self._onClickInstantEvent(result.iconElmtData.elmt, domEvt, evt);
       
  9340         } :
       
  9341         function(elmt, domEvt, target) {
       
  9342             return self._onClickInstantEvent(result.labelElmtData.elmt, domEvt, evt);
       
  9343         };
       
  9344 
       
  9345     SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler);
       
  9346     SimileAjax.DOM.registerEvent(result.impreciseTapeElmtData.elmt, "mousedown", clickHandler);
       
  9347 
       
  9348     if (iconData != null) {
       
  9349         SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler);
       
  9350         this._eventIdToElmt[evt.getID()] = result.iconElmtData.elmt;
       
  9351     } else {
       
  9352         this._eventIdToElmt[evt.getID()] = result.labelElmtData.elmt;
       
  9353     }
       
  9354 };
       
  9355 
       
  9356 Timeline.CompactEventPainter.prototype.paintPreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
       
  9357     var commonData = {
       
  9358         tooltip: evt.getProperty("tooltip") || evt.getText()
       
  9359     };
       
  9360 
       
  9361     var tapeData = {
       
  9362         start:          evt.getStart(),
       
  9363         end:            evt.getEnd(),
       
  9364         isInstant:      false
       
  9365     };
       
  9366 
       
  9367     var iconData = {
       
  9368         url: evt.getIcon()
       
  9369     };
       
  9370     if (iconData.url == null) {
       
  9371         iconData = null;
       
  9372     } else {
       
  9373         iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth;
       
  9374         iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight;
       
  9375     }
       
  9376 
       
  9377     var labelData = {
       
  9378         text:       evt.getText(),
       
  9379         color:      evt.getTextColor() || evt.getColor(),
       
  9380         className:  evt.getClassName()
       
  9381     };
       
  9382 
       
  9383     var result = this.paintTapeIconLabel(
       
  9384         evt.getLatestStart(),
       
  9385         commonData,
       
  9386         tapeData, // no tape data
       
  9387         iconData,
       
  9388         labelData,
       
  9389         metrics,
       
  9390         theme,
       
  9391         highlightIndex
       
  9392     );
       
  9393 
       
  9394     var self = this;
       
  9395     var clickHandler = iconData != null ?
       
  9396         function(elmt, domEvt, target) {
       
  9397             return self._onClickInstantEvent(result.iconElmtData.elmt, domEvt, evt);
       
  9398         } :
       
  9399         function(elmt, domEvt, target) {
       
  9400             return self._onClickInstantEvent(result.labelElmtData.elmt, domEvt, evt);
       
  9401         };
       
  9402 
       
  9403     SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler);
       
  9404     SimileAjax.DOM.registerEvent(result.tapeElmtData.elmt, "mousedown", clickHandler);
       
  9405 
       
  9406     if (iconData != null) {
       
  9407         SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler);
       
  9408         this._eventIdToElmt[evt.getID()] = result.iconElmtData.elmt;
       
  9409     } else {
       
  9410         this._eventIdToElmt[evt.getID()] = result.labelElmtData.elmt;
       
  9411     }
       
  9412 };
       
  9413 
       
  9414 Timeline.CompactEventPainter.prototype.paintImpreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
       
  9415     var commonData = {
       
  9416         tooltip: evt.getProperty("tooltip") || evt.getText()
       
  9417     };
       
  9418 
       
  9419     var tapeData = {
       
  9420         start:          evt.getStart(),
       
  9421         end:            evt.getEnd(),
       
  9422         latestStart:    evt.getLatestStart(),
       
  9423         earliestEnd:    evt.getEarliestEnd(),
       
  9424         isInstant:      false
       
  9425     };
       
  9426 
       
  9427     var iconData = {
       
  9428         url: evt.getIcon()
       
  9429     };
       
  9430     if (iconData.url == null) {
       
  9431         iconData = null;
       
  9432     } else {
       
  9433         iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth;
       
  9434         iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight;
       
  9435     }
       
  9436 
       
  9437     var labelData = {
       
  9438         text:       evt.getText(),
       
  9439         color:      evt.getTextColor() || evt.getColor(),
       
  9440         className:  evt.getClassName()
       
  9441     };
       
  9442 
       
  9443     var result = this.paintTapeIconLabel(
       
  9444         evt.getLatestStart(),
       
  9445         commonData,
       
  9446         tapeData, // no tape data
       
  9447         iconData,
       
  9448         labelData,
       
  9449         metrics,
       
  9450         theme,
       
  9451         highlightIndex
       
  9452     );
       
  9453 
       
  9454     var self = this;
       
  9455     var clickHandler = iconData != null ?
       
  9456         function(elmt, domEvt, target) {
       
  9457             return self._onClickInstantEvent(result.iconElmtData.elmt, domEvt, evt);
       
  9458         } :
       
  9459         function(elmt, domEvt, target) {
       
  9460             return self._onClickInstantEvent(result.labelElmtData.elmt, domEvt, evt);
       
  9461         };
       
  9462 
       
  9463     SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler);
       
  9464     SimileAjax.DOM.registerEvent(result.tapeElmtData.elmt, "mousedown", clickHandler);
       
  9465 
       
  9466     if (iconData != null) {
       
  9467         SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler);
       
  9468         this._eventIdToElmt[evt.getID()] = result.iconElmtData.elmt;
       
  9469     } else {
       
  9470         this._eventIdToElmt[evt.getID()] = result.labelElmtData.elmt;
       
  9471     }
       
  9472 };
       
  9473 
       
  9474 Timeline.CompactEventPainter.prototype.paintTapeIconLabel = function(
       
  9475     anchorDate,
       
  9476     commonData,
       
  9477     tapeData,
       
  9478     iconData,
       
  9479     labelData,
       
  9480     metrics,
       
  9481     theme,
       
  9482     highlightIndex
       
  9483 ) {
       
  9484     var band = this._band;
       
  9485     var getPixelOffset = function(date) {
       
  9486         return Math.round(band.dateToPixelOffset(date));
       
  9487     };
       
  9488 
       
  9489     var anchorPixel = getPixelOffset(anchorDate);
       
  9490     var newTracks = [];
       
  9491 
       
  9492     var tapeHeightOccupied = 0;         // how many pixels (vertically) the tape occupies, including bottom margin
       
  9493     var tapeTrackCount = 0;             // how many tracks the tape takes up, usually just 1
       
  9494     var tapeLastTrackExtraSpace = 0;    // on the last track that the tape occupies, how many pixels are left (for icon and label to occupy as well)
       
  9495     if (tapeData != null) {
       
  9496         tapeHeightOccupied = metrics.tapeHeight + metrics.tapeBottomMargin;
       
  9497         tapeTrackCount = Math.ceil(metrics.tapeHeight / metrics.trackHeight);
       
  9498 
       
  9499         var tapeEndPixelOffset = getPixelOffset(tapeData.end) - anchorPixel;
       
  9500         var tapeStartPixelOffset = getPixelOffset(tapeData.start) - anchorPixel;
       
  9501 
       
  9502         for (var t = 0; t < tapeTrackCount; t++) {
       
  9503             newTracks.push({ start: tapeStartPixelOffset, end: tapeEndPixelOffset });
       
  9504         }
       
  9505 
       
  9506         tapeLastTrackExtraSpace = metrics.trackHeight - (tapeHeightOccupied % metrics.tapeHeight);
       
  9507     }
       
  9508 
       
  9509     var iconStartPixelOffset = 0;        // where the icon starts compared to the anchor pixel;
       
  9510                                          // this can be negative if the icon is center-aligned around the anchor
       
  9511     var iconHorizontalSpaceOccupied = 0; // how many pixels the icon take up from the anchor pixel,
       
  9512                                          // including the gap between the icon and the label
       
  9513     if (iconData != null) {
       
  9514         if ("iconAlign" in iconData && iconData.iconAlign == "center") {
       
  9515             iconStartPixelOffset = -Math.floor(iconData.width / 2);
       
  9516         }
       
  9517         iconHorizontalSpaceOccupied = iconStartPixelOffset + iconData.width + metrics.iconLabelGap;
       
  9518 
       
  9519         if (tapeTrackCount > 0) {
       
  9520             newTracks[tapeTrackCount - 1].end = Math.max(newTracks[tapeTrackCount - 1].end, iconHorizontalSpaceOccupied);
       
  9521         }
       
  9522 
       
  9523         var iconHeight = iconData.height + metrics.iconBottomMargin + tapeLastTrackExtraSpace;
       
  9524         while (iconHeight > 0) {
       
  9525             newTracks.push({ start: iconStartPixelOffset, end: iconHorizontalSpaceOccupied });
       
  9526             iconHeight -= metrics.trackHeight;
       
  9527         }
       
  9528     }
       
  9529 
       
  9530     var text = labelData.text;
       
  9531     var labelSize = this._frc.computeSize(text);
       
  9532     var labelHeight = labelSize.height + metrics.labelBottomMargin + tapeLastTrackExtraSpace;
       
  9533     var labelEndPixelOffset = iconHorizontalSpaceOccupied + labelSize.width + metrics.labelRightMargin;
       
  9534     if (tapeTrackCount > 0) {
       
  9535         newTracks[tapeTrackCount - 1].end = Math.max(newTracks[tapeTrackCount - 1].end, labelEndPixelOffset);
       
  9536     }
       
  9537     for (var i = 0; labelHeight > 0; i++) {
       
  9538         if (tapeTrackCount + i < newTracks.length) {
       
  9539             var track = newTracks[tapeTrackCount + i];
       
  9540             track.end = labelEndPixelOffset;
       
  9541         } else {
       
  9542             newTracks.push({ start: 0, end: labelEndPixelOffset });
       
  9543         }
       
  9544         labelHeight -= metrics.trackHeight;
       
  9545     }
       
  9546 
       
  9547     /*
       
  9548      *  Try to fit the new track on top of the existing tracks, then
       
  9549      *  render the various elements.
       
  9550      */
       
  9551     var firstTrack = this._fitTracks(anchorPixel, newTracks);
       
  9552     var verticalPixelOffset = firstTrack * metrics.trackHeight + metrics.trackOffset;
       
  9553     var result = {};
       
  9554 
       
  9555     result.labelElmtData = this._paintEventLabel(
       
  9556         commonData,
       
  9557         labelData,
       
  9558         anchorPixel + iconHorizontalSpaceOccupied,
       
  9559         verticalPixelOffset + tapeHeightOccupied,
       
  9560         labelSize.width,
       
  9561         labelSize.height,
       
  9562         theme
       
  9563     );
       
  9564 
       
  9565     if (tapeData != null) {
       
  9566         if ("latestStart" in tapeData || "earliestEnd" in tapeData) {
       
  9567             result.impreciseTapeElmtData = this._paintEventTape(
       
  9568                 commonData,
       
  9569                 tapeData,
       
  9570                 metrics.tapeHeight,
       
  9571                 verticalPixelOffset,
       
  9572                 getPixelOffset(tapeData.start),
       
  9573                 getPixelOffset(tapeData.end),
       
  9574                 theme.event.duration.impreciseColor,
       
  9575                 theme.event.duration.impreciseOpacity,
       
  9576                 metrics,
       
  9577                 theme
       
  9578             );
       
  9579         }
       
  9580         if (!tapeData.isInstant && "start" in tapeData && "end" in tapeData) {
       
  9581             result.tapeElmtData = this._paintEventTape(
       
  9582                 commonData,
       
  9583                 tapeData,
       
  9584                 metrics.tapeHeight,
       
  9585                 verticalPixelOffset,
       
  9586                 anchorPixel,
       
  9587                 getPixelOffset("earliestEnd" in tapeData ? tapeData.earliestEnd : tapeData.end),
       
  9588                 tapeData.color,
       
  9589                 100,
       
  9590                 metrics,
       
  9591                 theme
       
  9592             );
       
  9593         }
       
  9594     }
       
  9595 
       
  9596     if (iconData != null) {
       
  9597         result.iconElmtData = this._paintEventIcon(
       
  9598             commonData,
       
  9599             iconData,
       
  9600             verticalPixelOffset + tapeHeightOccupied,
       
  9601             anchorPixel + iconStartPixelOffset,
       
  9602             metrics,
       
  9603             theme
       
  9604         );
       
  9605     }
       
  9606     //this._createHighlightDiv(highlightIndex, iconElmtData, theme);
       
  9607 
       
  9608     return result;
       
  9609 };
       
  9610 
       
  9611 Timeline.CompactEventPainter.prototype._fitTracks = function(anchorPixel, newTracks) {
       
  9612     var firstTrack;
       
  9613     for (firstTrack = 0; firstTrack < this._tracks.length; firstTrack++) {
       
  9614         var fit = true;
       
  9615         for (var j = 0; j < newTracks.length && (firstTrack + j) < this._tracks.length; j++) {
       
  9616             var existingTrack = this._tracks[firstTrack + j];
       
  9617             var newTrack = newTracks[j];
       
  9618             if (anchorPixel + newTrack.start < existingTrack) {
       
  9619                 fit = false;
       
  9620                 break;
       
  9621             }
       
  9622         }
       
  9623 
       
  9624         if (fit) {
       
  9625             break;
       
  9626         }
       
  9627     }
       
  9628     for (var i = 0; i < newTracks.length; i++) {
       
  9629         this._tracks[firstTrack + i] = anchorPixel + newTracks[i].end;
       
  9630     }
       
  9631 
       
  9632     return firstTrack;
       
  9633 };
       
  9634 
       
  9635 
       
  9636 Timeline.CompactEventPainter.prototype._paintEventIcon = function(commonData, iconData, top, left, metrics, theme) {
       
  9637     var img = SimileAjax.Graphics.createTranslucentImage(iconData.url);
       
  9638     var iconDiv = this._timeline.getDocument().createElement("div");
       
  9639     iconDiv.className = 'timeline-event-icon' + ("className" in iconData ? (" " + iconData.className) : "");
       
  9640     iconDiv.style.left = left + "px";
       
  9641     iconDiv.style.top = top + "px";
       
  9642     iconDiv.appendChild(img);
       
  9643 
       
  9644     if ("tooltip" in commonData && typeof commonData.tooltip == "string") {
       
  9645         iconDiv.title = commonData.tooltip;
       
  9646     }
       
  9647 
       
  9648     this._eventLayer.appendChild(iconDiv);
       
  9649 
       
  9650     return {
       
  9651         left:   left,
       
  9652         top:    top,
       
  9653         width:  metrics.iconWidth,
       
  9654         height: metrics.iconHeight,
       
  9655         elmt:   iconDiv
       
  9656     };
       
  9657 };
       
  9658 
       
  9659 Timeline.CompactEventPainter.prototype._paintEventLabel = function(commonData, labelData, left, top, width, height, theme) {
       
  9660     var doc = this._timeline.getDocument();
       
  9661 
       
  9662     var labelDiv = doc.createElement("div");
       
  9663     labelDiv.className = 'timeline-event-label';
       
  9664 
       
  9665     labelDiv.style.left = left + "px";
       
  9666     labelDiv.style.width = (width + 1) + "px";
       
  9667     labelDiv.style.top = top + "px";
       
  9668     labelDiv.innerHTML = labelData.text;
       
  9669 
       
  9670     if ("tooltip" in commonData && typeof commonData.tooltip == "string") {
       
  9671         labelDiv.title = commonData.tooltip;
       
  9672     }
       
  9673     if ("color" in labelData && typeof labelData.color == "string") {
       
  9674         labelDiv.style.color = labelData.color;
       
  9675     }
       
  9676     if ("className" in labelData && typeof labelData.className == "string") {
       
  9677         labelDiv.className += ' ' + labelData.className;
       
  9678     }
       
  9679 
       
  9680     this._eventLayer.appendChild(labelDiv);
       
  9681 
       
  9682     return {
       
  9683         left:   left,
       
  9684         top:    top,
       
  9685         width:  width,
       
  9686         height: height,
       
  9687         elmt:   labelDiv
       
  9688     };
       
  9689 };
       
  9690 
       
  9691 Timeline.CompactEventPainter.prototype._paintEventTape = function(
       
  9692     commonData, tapeData, height, top, startPixel, endPixel, color, opacity, metrics, theme) {
       
  9693 
       
  9694     var width = endPixel - startPixel;
       
  9695 
       
  9696     var tapeDiv = this._timeline.getDocument().createElement("div");
       
  9697     tapeDiv.className = "timeline-event-tape"
       
  9698 
       
  9699     tapeDiv.style.left = startPixel + "px";
       
  9700     tapeDiv.style.top = top + "px";
       
  9701     tapeDiv.style.width = width + "px";
       
  9702     tapeDiv.style.height = height + "px";
       
  9703 
       
  9704     if ("tooltip" in commonData && typeof commonData.tooltip == "string") {
       
  9705         tapeDiv.title = commonData.tooltip;
       
  9706     }
       
  9707     if (color != null && typeof tapeData.color == "string") {
       
  9708         tapeDiv.style.backgroundColor = color;
       
  9709     }
       
  9710 
       
  9711     if ("backgroundImage" in tapeData && typeof tapeData.backgroundImage == "string") {
       
  9712         tapeDiv.style.backgroundImage = "url(" + backgroundImage + ")";
       
  9713         tapeDiv.style.backgroundRepeat =
       
  9714             ("backgroundRepeat" in tapeData && typeof tapeData.backgroundRepeat == "string")
       
  9715                 ? tapeData.backgroundRepeat : 'repeat';
       
  9716     }
       
  9717 
       
  9718     SimileAjax.Graphics.setOpacity(tapeDiv, opacity);
       
  9719 
       
  9720     if ("className" in tapeData && typeof tapeData.className == "string") {
       
  9721         tapeDiv.className += ' ' + tapeData.className;
       
  9722     }
       
  9723 
       
  9724     this._eventLayer.appendChild(tapeDiv);
       
  9725 
       
  9726     return {
       
  9727         left:   startPixel,
       
  9728         top:    top,
       
  9729         width:  width,
       
  9730         height: height,
       
  9731         elmt:   tapeDiv
       
  9732     };
       
  9733 }
       
  9734 
       
  9735 Timeline.CompactEventPainter.prototype._createHighlightDiv = function(highlightIndex, dimensions, theme) {
       
  9736     if (highlightIndex >= 0) {
       
  9737         var doc = this._timeline.getDocument();
       
  9738         var eventTheme = theme.event;
       
  9739 
       
  9740         var color = eventTheme.highlightColors[Math.min(highlightIndex, eventTheme.highlightColors.length - 1)];
       
  9741 
       
  9742         var div = doc.createElement("div");
       
  9743         div.style.position = "absolute";
       
  9744         div.style.overflow = "hidden";
       
  9745         div.style.left =    (dimensions.left - 2) + "px";
       
  9746         div.style.width =   (dimensions.width + 4) + "px";
       
  9747         div.style.top =     (dimensions.top - 2) + "px";
       
  9748         div.style.height =  (dimensions.height + 4) + "px";
       
  9749 //        div.style.background = color;
       
  9750 
       
  9751         this._highlightLayer.appendChild(div);
       
  9752     }
       
  9753 };
       
  9754 
       
  9755 Timeline.CompactEventPainter.prototype._onClickMultiplePreciseInstantEvent = function(icon, domEvt, events) {
       
  9756     var c = SimileAjax.DOM.getPageCoordinates(icon);
       
  9757     this._showBubble(
       
  9758         c.left + Math.ceil(icon.offsetWidth / 2),
       
  9759         c.top + Math.ceil(icon.offsetHeight / 2),
       
  9760         events
       
  9761     );
       
  9762 
       
  9763     var ids = [];
       
  9764     for (var i = 0; i < events.length; i++) {
       
  9765         ids.push(events[i].getID());
       
  9766     }
       
  9767     this._fireOnSelect(ids);
       
  9768 
       
  9769     domEvt.cancelBubble = true;
       
  9770     SimileAjax.DOM.cancelEvent(domEvt);
       
  9771 
       
  9772     return false;
       
  9773 };
       
  9774 
       
  9775 Timeline.CompactEventPainter.prototype._onClickInstantEvent = function(icon, domEvt, evt) {
       
  9776     var c = SimileAjax.DOM.getPageCoordinates(icon);
       
  9777     this._showBubble(
       
  9778         c.left + Math.ceil(icon.offsetWidth / 2),
       
  9779         c.top + Math.ceil(icon.offsetHeight / 2),
       
  9780         [evt]
       
  9781     );
       
  9782     this._fireOnSelect([evt.getID()]);
       
  9783 
       
  9784     domEvt.cancelBubble = true;
       
  9785     SimileAjax.DOM.cancelEvent(domEvt);
       
  9786     return false;
       
  9787 };
       
  9788 
       
  9789 Timeline.CompactEventPainter.prototype._onClickDurationEvent = function(target, domEvt, evt) {
       
  9790     if ("pageX" in domEvt) {
       
  9791         var x = domEvt.pageX;
       
  9792         var y = domEvt.pageY;
       
  9793     } else {
       
  9794         var c = SimileAjax.DOM.getPageCoordinates(target);
       
  9795         var x = domEvt.offsetX + c.left;
       
  9796         var y = domEvt.offsetY + c.top;
       
  9797     }
       
  9798     this._showBubble(x, y, [evt]);
       
  9799     this._fireOnSelect([evt.getID()]);
       
  9800 
       
  9801     domEvt.cancelBubble = true;
       
  9802     SimileAjax.DOM.cancelEvent(domEvt);
       
  9803     return false;
       
  9804 };
       
  9805 
       
  9806 Timeline.CompactEventPainter.prototype.showBubble = function(evt) {
       
  9807     var elmt = this._eventIdToElmt[evt.getID()];
       
  9808     if (elmt) {
       
  9809         var c = SimileAjax.DOM.getPageCoordinates(elmt);
       
  9810         this._showBubble(c.left + elmt.offsetWidth / 2, c.top + elmt.offsetHeight / 2, [evt]);
       
  9811     }
       
  9812 };
       
  9813 
       
  9814 Timeline.CompactEventPainter.prototype._showBubble = function(x, y, evts) {
       
  9815     var div = document.createElement("div");
       
  9816 
       
  9817     evts = ("fillInfoBubble" in evts) ? [evts] : evts;
       
  9818     for (var i = 0; i < evts.length; i++) {
       
  9819         var div2 = document.createElement("div");
       
  9820         div.appendChild(div2);
       
  9821 
       
  9822         evts[i].fillInfoBubble(div2, this._params.theme, this._band.getLabeller());
       
  9823     }
       
  9824 
       
  9825     SimileAjax.WindowManager.cancelPopups();
       
  9826     SimileAjax.Graphics.createBubbleForContentAndPoint(div, x, y, this._params.theme.event.bubble.width);
       
  9827 };
       
  9828 
       
  9829 Timeline.CompactEventPainter.prototype._fireOnSelect = function(eventIDs) {
       
  9830     for (var i = 0; i < this._onSelectListeners.length; i++) {
       
  9831         this._onSelectListeners[i](eventIDs);
       
  9832     }
       
  9833 };
       
  9834 /*==================================================
       
  9835  *  Span Highlight Decorator
       
  9836  *==================================================
       
  9837  */
       
  9838 
       
  9839 Timeline.SpanHighlightDecorator = function(params) {
       
  9840     // When evaluating params, test against null. Not "p in params". Testing against
       
  9841     // null enables caller to explicitly request the default. Testing against "in" means
       
  9842     // that the param has to be ommitted to get the default.
       
  9843     this._unit = params.unit != null ? params.unit : SimileAjax.NativeDateUnit;
       
  9844     this._startDate = (typeof params.startDate == "string") ?
       
  9845         this._unit.parseFromObject(params.startDate) : params.startDate;
       
  9846     this._endDate = (typeof params.endDate == "string") ?
       
  9847         this._unit.parseFromObject(params.endDate) : params.endDate;
       
  9848     this._startLabel = params.startLabel != null ? params.startLabel : ""; // not null!
       
  9849     this._endLabel   = params.endLabel   != null ? params.endLabel   : ""; // not null!
       
  9850     this._color = params.color;
       
  9851     this._cssClass = params.cssClass != null ? params.cssClass : null;
       
  9852     this._opacity = params.opacity != null ? params.opacity : 100;
       
  9853          // Default z is 10, behind everything but background grid.
       
  9854          // If inFront, then place just behind events, in front of everything else
       
  9855     this._zIndex = (params.inFront != null && params.inFront) ? 113 : 10;
       
  9856 };
       
  9857 
       
  9858 Timeline.SpanHighlightDecorator.prototype.initialize = function(band, timeline) {
       
  9859     this._band = band;
       
  9860     this._timeline = timeline;
       
  9861 
       
  9862     this._layerDiv = null;
       
  9863 };
       
  9864 
       
  9865 Timeline.SpanHighlightDecorator.prototype.paint = function() {
       
  9866     if (this._layerDiv != null) {
       
  9867         this._band.removeLayerDiv(this._layerDiv);
       
  9868     }
       
  9869     this._layerDiv = this._band.createLayerDiv(this._zIndex);
       
  9870     this._layerDiv.setAttribute("name", "span-highlight-decorator"); // for debugging
       
  9871     this._layerDiv.style.display = "none";
       
  9872 
       
  9873     var minDate = this._band.getMinDate();
       
  9874     var maxDate = this._band.getMaxDate();
       
  9875 
       
  9876     if (this._unit.compare(this._startDate, maxDate) < 0 &&
       
  9877         this._unit.compare(this._endDate, minDate) > 0) {
       
  9878 
       
  9879         minDate = this._unit.later(minDate, this._startDate);
       
  9880         maxDate = this._unit.earlier(maxDate, this._endDate);
       
  9881 
       
  9882         var minPixel = this._band.dateToPixelOffset(minDate);
       
  9883         var maxPixel = this._band.dateToPixelOffset(maxDate);
       
  9884 
       
  9885         var doc = this._timeline.getDocument();
       
  9886 
       
  9887         var createTable = function() {
       
  9888             var table = doc.createElement("table");
       
  9889             table.insertRow(0).insertCell(0);
       
  9890             return table;
       
  9891         };
       
  9892 
       
  9893         var div = doc.createElement("div");
       
  9894         div.className='timeline-highlight-decorator'
       
  9895         if(this._cssClass) {
       
  9896         	  div.className += ' ' + this._cssClass;
       
  9897         }
       
  9898         if(this._color != null) {
       
  9899         	  div.style.backgroundColor = this._color;
       
  9900         }
       
  9901         if (this._opacity < 100) {
       
  9902             SimileAjax.Graphics.setOpacity(div, this._opacity);
       
  9903         }
       
  9904         this._layerDiv.appendChild(div);
       
  9905 
       
  9906         var tableStartLabel = createTable();
       
  9907         tableStartLabel.className = 'timeline-highlight-label timeline-highlight-label-start'
       
  9908         var tdStart =  tableStartLabel.rows[0].cells[0]
       
  9909         tdStart.innerHTML = this._startLabel;
       
  9910         if (this._cssClass) {
       
  9911         	  tdStart.className = 'label_' + this._cssClass;
       
  9912         }
       
  9913         this._layerDiv.appendChild(tableStartLabel);
       
  9914 
       
  9915         var tableEndLabel = createTable();
       
  9916         tableEndLabel.className = 'timeline-highlight-label timeline-highlight-label-end'
       
  9917         var tdEnd = tableEndLabel.rows[0].cells[0]
       
  9918         tdEnd.innerHTML = this._endLabel;
       
  9919         if (this._cssClass) {
       
  9920         	   tdEnd.className = 'label_' + this._cssClass;
       
  9921         }
       
  9922         this._layerDiv.appendChild(tableEndLabel);
       
  9923 
       
  9924         if (this._timeline.isHorizontal()){
       
  9925             div.style.left = minPixel + "px";
       
  9926             div.style.width = (maxPixel - minPixel) + "px";
       
  9927 
       
  9928             tableStartLabel.style.right = (this._band.getTotalViewLength() - minPixel) + "px";
       
  9929             tableStartLabel.style.width = (this._startLabel.length) + "em";
       
  9930 
       
  9931             tableEndLabel.style.left = maxPixel + "px";
       
  9932             tableEndLabel.style.width = (this._endLabel.length) + "em";
       
  9933 
       
  9934         } else {
       
  9935             div.style.top = minPixel + "px";
       
  9936             div.style.height = (maxPixel - minPixel) + "px";
       
  9937 
       
  9938             tableStartLabel.style.bottom = minPixel + "px";
       
  9939             tableStartLabel.style.height = "1.5px";
       
  9940 
       
  9941             tableEndLabel.style.top = maxPixel + "px";
       
  9942             tableEndLabel.style.height = "1.5px";
       
  9943         }
       
  9944     }
       
  9945     this._layerDiv.style.display = "block";
       
  9946 };
       
  9947 
       
  9948 Timeline.SpanHighlightDecorator.prototype.softPaint = function() {
       
  9949 };
       
  9950 
       
  9951 /*==================================================
       
  9952  *  Point Highlight Decorator
       
  9953  *==================================================
       
  9954  */
       
  9955 
       
  9956 Timeline.PointHighlightDecorator = function(params) {
       
  9957     this._unit = params.unit != null ? params.unit : SimileAjax.NativeDateUnit;
       
  9958     this._date = (typeof params.date == "string") ?
       
  9959         this._unit.parseFromObject(params.date) : params.date;
       
  9960     this._width = params.width != null ? params.width : 10;
       
  9961       // Since the width is used to calculate placements (see minPixel, below), we
       
  9962       // specify width here, not in css.
       
  9963     this._color = params.color;
       
  9964     this._cssClass = params.cssClass != null ? params.cssClass : '';
       
  9965     this._opacity = params.opacity != null ? params.opacity : 100;
       
  9966 };
       
  9967 
       
  9968 Timeline.PointHighlightDecorator.prototype.initialize = function(band, timeline) {
       
  9969     this._band = band;
       
  9970     this._timeline = timeline;
       
  9971     this._layerDiv = null;
       
  9972 };
       
  9973 
       
  9974 Timeline.PointHighlightDecorator.prototype.paint = function() {
       
  9975     if (this._layerDiv != null) {
       
  9976         this._band.removeLayerDiv(this._layerDiv);
       
  9977     }
       
  9978     this._layerDiv = this._band.createLayerDiv(10);
       
  9979     this._layerDiv.setAttribute("name", "span-highlight-decorator"); // for debugging
       
  9980     this._layerDiv.style.display = "none";
       
  9981 
       
  9982     var minDate = this._band.getMinDate();
       
  9983     var maxDate = this._band.getMaxDate();
       
  9984 
       
  9985     if (this._unit.compare(this._date, maxDate) < 0 &&
       
  9986         this._unit.compare(this._date, minDate) > 0) {
       
  9987 
       
  9988         var pixel = this._band.dateToPixelOffset(this._date);
       
  9989         var minPixel = pixel - Math.round(this._width / 2);
       
  9990 
       
  9991         var doc = this._timeline.getDocument();
       
  9992 
       
  9993         var div = doc.createElement("div");
       
  9994         div.className='timeline-highlight-point-decorator';
       
  9995         div.className += ' ' + this._cssClass;
       
  9996 
       
  9997         if(this._color != null) {
       
  9998         	  div.style.backgroundColor = this._color;
       
  9999         }
       
 10000         if (this._opacity < 100) {
       
 10001             SimileAjax.Graphics.setOpacity(div, this._opacity);
       
 10002         }
       
 10003         this._layerDiv.appendChild(div);
       
 10004 
       
 10005         if (this._timeline.isHorizontal()) {
       
 10006             div.style.left = minPixel + "px";
       
 10007             div.style.width = this._width;
       
 10008         } else {
       
 10009             div.style.top = minPixel + "px";
       
 10010             div.style.height = this._width;
       
 10011         }
       
 10012     }
       
 10013     this._layerDiv.style.display = "block";
       
 10014 };
       
 10015 
       
 10016 Timeline.PointHighlightDecorator.prototype.softPaint = function() {
       
 10017 };
       
 10018 /*==================================================
       
 10019  *  Default Unit
       
 10020  *==================================================
       
 10021  */
       
 10022 
       
 10023 Timeline.NativeDateUnit = new Object();
       
 10024 
       
 10025 Timeline.NativeDateUnit.createLabeller = function(locale, timeZone) {
       
 10026     return new Timeline.GregorianDateLabeller(locale, timeZone);
       
 10027 };
       
 10028 
       
 10029 Timeline.NativeDateUnit.makeDefaultValue = function() {
       
 10030     return new Date();
       
 10031 };
       
 10032 
       
 10033 Timeline.NativeDateUnit.cloneValue = function(v) {
       
 10034     return new Date(v.getTime());
       
 10035 };
       
 10036 
       
 10037 Timeline.NativeDateUnit.getParser = function(format) {
       
 10038     if (typeof format == "string") {
       
 10039         format = format.toLowerCase();
       
 10040     }
       
 10041     return (format == "iso8601" || format == "iso 8601") ?
       
 10042         Timeline.DateTime.parseIso8601DateTime : 
       
 10043         Timeline.DateTime.parseGregorianDateTime;
       
 10044 };
       
 10045 
       
 10046 Timeline.NativeDateUnit.parseFromObject = function(o) {
       
 10047     return Timeline.DateTime.parseGregorianDateTime(o);
       
 10048 };
       
 10049 
       
 10050 Timeline.NativeDateUnit.toNumber = function(v) {
       
 10051     return v.getTime();
       
 10052 };
       
 10053 
       
 10054 Timeline.NativeDateUnit.fromNumber = function(n) {
       
 10055     return new Date(n);
       
 10056 };
       
 10057 
       
 10058 Timeline.NativeDateUnit.compare = function(v1, v2) {
       
 10059     var n1, n2;
       
 10060     if (typeof v1 == "object") {
       
 10061         n1 = v1.getTime();
       
 10062     } else {
       
 10063         n1 = Number(v1);
       
 10064     }
       
 10065     if (typeof v2 == "object") {
       
 10066         n2 = v2.getTime();
       
 10067     } else {
       
 10068         n2 = Number(v2);
       
 10069     }
       
 10070 
       
 10071     return n1 - n2;
       
 10072 };
       
 10073 
       
 10074 Timeline.NativeDateUnit.earlier = function(v1, v2) {
       
 10075     return Timeline.NativeDateUnit.compare(v1, v2) < 0 ? v1 : v2;
       
 10076 };
       
 10077 
       
 10078 Timeline.NativeDateUnit.later = function(v1, v2) {
       
 10079     return Timeline.NativeDateUnit.compare(v1, v2) > 0 ? v1 : v2;
       
 10080 };
       
 10081 
       
 10082 Timeline.NativeDateUnit.change = function(v, n) {
       
 10083     return new Date(v.getTime() + n);
       
 10084 };
       
 10085 
       
 10086 /*==================================================
       
 10087  *  Common localization strings
       
 10088  *==================================================
       
 10089  */
       
 10090 
       
 10091 Timeline.strings["fr"] = {
       
 10092     wikiLinkLabel:  "Discute"
       
 10093 };
       
 10094 
       
 10095 /*==================================================
       
 10096  *  Localization of labellers.js
       
 10097  *==================================================
       
 10098  */
       
 10099 
       
 10100 Timeline.GregorianDateLabeller.monthNames["fr"] = [
       
 10101     "jan", "fev", "mar", "avr", "mai", "jui", "jui", "aou", "sep", "oct", "nov", "dec"
       
 10102 ];
       
 10103 /*==================================================
       
 10104  *  Common localization strings
       
 10105  *==================================================
       
 10106  */
       
 10107 
       
 10108 Timeline.strings["en"] = {
       
 10109     wikiLinkLabel:  "Discuss"
       
 10110 };
       
 10111 
       
 10112 /*==================================================
       
 10113  *  Localization of labellers.js
       
 10114  *==================================================
       
 10115  */
       
 10116 
       
 10117 Timeline.GregorianDateLabeller.monthNames["en"] = [
       
 10118     "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
       
 10119 ];
       
 10120 
       
 10121 Timeline.GregorianDateLabeller.dayNames["en"] = [
       
 10122     "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
       
 10123 ];