~ubuntu-branches/ubuntu/utopic/yelp/utopic-proposed

« back to all changes in this revision

Viewing changes to data/mathjax/unpacked/MathJax.js

  • Committer: Package Import Robot
  • Author(s): Matthew Fischer
  • Date: 2013-05-25 20:01:06 UTC
  • mfrom: (1.1.67) (131.1.1 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130525200106-4re1oimhqy8exd9b
Tags: 3.8.1-0ubuntu1
* New upstream release (LP: #1184244)
  - Added test token for classic mode (Matthias Clasen)
  - Updated translations
  - Stop checking for pangox and X11 (Emilio Pozuelo Monfort)
  - Add keywords to the desktop file (Matthias Clasen)
  - Fixed handling of xref links with anchors, #686095 (Tails developers)
  - Fixed various memory management bugs, #683100 (Carlos Garcia Campos)
  - Added local copy of MathJax for MathML display (Shaun McCance)
  - Added support for xdg help system in All Documents (Shaun McCance)
  - Fixed if:test="action:install" (Shaun McCance)
  - Switched to using 'itstool -j' for XSL domain (Shaun McCance)
* Refreshed patches, removed some patches that have been unused for some
  time.
  - debian/patches/00_no_am_gnu_gettext.patch - Removed, unused
  - debian/patches/02_man-utf8.patch - Removed, unused
  - debian/patches/04_man-utf8.patch - Removed, unused

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*************************************************************
 
2
 *
 
3
 *  MathJax.js
 
4
 *  
 
5
 *  The main support code for the MathJax Hub, including the
 
6
 *  Ajax, Callback, Messaging, and Object-Oriented Programming
 
7
 *  libraries, as well as the base Jax classes, and startup
 
8
 *  processing code.
 
9
 *  
 
10
 *  ---------------------------------------------------------------------
 
11
 *  
 
12
 *  Copyright (c) 2009-2012 Design Science, Inc.
 
13
 * 
 
14
 *  Licensed under the Apache License, Version 2.0 (the "License");
 
15
 *  you may not use this file except in compliance with the License.
 
16
 *  You may obtain a copy of the License at
 
17
 * 
 
18
 *      http://www.apache.org/licenses/LICENSE-2.0
 
19
 * 
 
20
 *  Unless required by applicable law or agreed to in writing, software
 
21
 *  distributed under the License is distributed on an "AS IS" BASIS,
 
22
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
23
 *  See the License for the specific language governing permissions and
 
24
 *  limitations under the License.
 
25
 */
 
26
 
 
27
if (document.getElementById && document.childNodes && document.createElement) {
 
28
 
 
29
if (!window.MathJax) {window.MathJax= {}}
 
30
if (!MathJax.Hub) {  // skip if already loaded
 
31
  
 
32
MathJax.version = "2.1";
 
33
MathJax.fileversion = "2.1";
 
34
 
 
35
/**********************************************************/
 
36
 
 
37
(function (BASENAME) {
 
38
  var BASE = window[BASENAME];
 
39
  if (!BASE) {BASE = window[BASENAME] = {}}
 
40
 
 
41
  var PROTO = [];  // a static object used to indicate when a prototype is being created
 
42
  var OBJECT = function (def) {
 
43
    var obj = def.constructor; if (!obj) {obj = new Function("")}
 
44
    for (var id in def) {if (id !== 'constructor' && def.hasOwnProperty(id)) {obj[id] = def[id]}}
 
45
    return obj;
 
46
  };
 
47
  var CONSTRUCTOR = function () {
 
48
    return new Function ("return arguments.callee.Init.call(this,arguments)");
 
49
  };
 
50
  //
 
51
  //  Test for Safari 2.x bug (can't replace prototype for result of new Function()).
 
52
  //  (We don't use this version for everyone since it is a closure and we don't need that).
 
53
  //
 
54
  var BUGTEST = CONSTRUCTOR(); BUGTEST.prototype = {bug_test: 1};
 
55
  if (!BUGTEST.prototype.bug_test) {
 
56
    CONSTRUCTOR = function () {
 
57
      return function () {return arguments.callee.Init.call(this,arguments)};
 
58
    };
 
59
  };
 
60
 
 
61
  BASE.Object = OBJECT({
 
62
    constructor: CONSTRUCTOR(),
 
63
    
 
64
    Subclass: function (def,classdef) {
 
65
      var obj = CONSTRUCTOR();
 
66
      obj.SUPER = this; obj.Init = this.Init;
 
67
      obj.Subclass = this.Subclass; obj.Augment = this.Augment;
 
68
      obj.protoFunction = this.protoFunction;
 
69
      obj.can = this.can; obj.has = this.has; obj.isa = this.isa;
 
70
      obj.prototype = new this(PROTO);
 
71
      obj.prototype.constructor = obj;  // the real constructor
 
72
      obj.Augment(def,classdef);
 
73
      return obj;
 
74
    },
 
75
  
 
76
    Init: function (args) {
 
77
      var obj = this;
 
78
      if (args.length === 1 && args[0] === PROTO) {return obj}
 
79
      if (!(obj instanceof args.callee)) {obj = new args.callee(PROTO)}
 
80
      return obj.Init.apply(obj,args) || obj;
 
81
    },
 
82
    
 
83
    Augment: function (def,classdef) {
 
84
      var id;
 
85
      if (def != null) {
 
86
        for (id in def) {if (def.hasOwnProperty(id)) {this.protoFunction(id,def[id])}}
 
87
        // MSIE doesn't list toString even if it is not native so handle it separately
 
88
        if (def.toString !== this.prototype.toString && def.toString !== {}.toString)
 
89
          {this.protoFunction('toString',def.toString)}
 
90
      }
 
91
      if (classdef != null) {
 
92
        for (id in classdef) {if (classdef.hasOwnProperty(id)) {this[id] = classdef[id]}}
 
93
      }
 
94
      return this;
 
95
    },
 
96
  
 
97
    protoFunction: function (id,def) {
 
98
      this.prototype[id] = def;
 
99
      if (typeof def === "function") {def.SUPER = this.SUPER.prototype}
 
100
    },
 
101
  
 
102
    prototype: {
 
103
      Init: function () {},
 
104
      SUPER: function (fn) {return fn.callee.SUPER},
 
105
      can: function (method) {return typeof(this[method]) === "function"},
 
106
      has: function (property) {return typeof(this[property]) !== "undefined"},
 
107
      isa: function (obj) {return (obj instanceof Object) && (this instanceof obj)}
 
108
    },
 
109
  
 
110
    can: function (method)   {return this.prototype.can.call(this,method)},
 
111
    has: function (property) {return this.prototype.has.call(this,property)},
 
112
    isa: function (obj) {
 
113
      var constructor = this;
 
114
      while (constructor) {
 
115
        if (constructor === obj) {return true} else {constructor = constructor.SUPER}
 
116
      }
 
117
      return false;
 
118
    },
 
119
 
 
120
 
 
121
    SimpleSUPER: OBJECT({
 
122
      constructor: function (def) {return this.SimpleSUPER.define(def)},
 
123
 
 
124
      define: function (src) {
 
125
        var dst = {};
 
126
        if (src != null) {
 
127
          for (var id in src) {if (src.hasOwnProperty(id)) {dst[id] = this.wrap(id,src[id])}}
 
128
          // MSIE doesn't list toString even if it is not native so handle it separately
 
129
          if (src.toString !== this.prototype.toString && src.toString !== {}.toString)
 
130
            {dst.toString = this.wrap('toString',src.toString)}
 
131
        }
 
132
        return dst;
 
133
      },
 
134
 
 
135
      wrap: function (id,f) {
 
136
        if (typeof(f) === 'function' && f.toString().match(/\.\s*SUPER\s*\(/)) {
 
137
          var fn = new Function(this.wrapper);
 
138
          fn.label = id; fn.original = f; f = fn;
 
139
          fn.toString = this.stringify;
 
140
        }
 
141
        return f;
 
142
      },
 
143
 
 
144
      wrapper: function () {
 
145
        var fn = arguments.callee;
 
146
        this.SUPER = fn.SUPER[fn.label];
 
147
        try {var result = fn.original.apply(this,arguments)}
 
148
          catch (err) {delete this.SUPER; throw err}
 
149
        delete this.SUPER;
 
150
        return result;
 
151
      }.toString().replace(/^\s*function\s*\(\)\s*\{\s*/i,"").replace(/\s*\}\s*$/i,""),
 
152
 
 
153
      toString: function () {
 
154
        return this.original.toString.apply(this.original,arguments);
 
155
      }
 
156
    })
 
157
  });
 
158
 
 
159
})("MathJax");
 
160
 
 
161
/**********************************************************/
 
162
 
 
163
/*
 
164
 *  Create a callback function from various forms of data:
 
165
 *  
 
166
 *     MathJax.Callback(fn)    -- callback to a function
 
167
 *
 
168
 *     MathJax.Callback([fn])  -- callback to function
 
169
 *     MathJax.Callback([fn,data...])
 
170
 *                             -- callback to function with given data as arguments
 
171
 *     MathJax.Callback([object,fn])
 
172
 *                             -- call fn with object as "this"
 
173
 *     MathJax.Callback([object,fn,data...])
 
174
 *                             -- call fn with object as "this" and data as arguments
 
175
 *     MathJax.Callback(["method",object])
 
176
 *                             -- call method of object wth object as "this"
 
177
 *     MathJax.Callback(["method",object,data...])
 
178
 *                             -- as above, but with data as arguments to method
 
179
 *
 
180
 *     MathJax.Callback({hook: fn, data: [...], object: this})
 
181
 *                             -- give function, data, and object to act as "this" explicitly
 
182
 *
 
183
 *     MathJax.Callback("code")  -- callback that compiles and executes a string
 
184
 *
 
185
 *     MathJax.Callback([...],i)
 
186
 *                             -- use slice of array starting at i and interpret
 
187
 *                                result as above.  (Used for passing "arguments" array
 
188
 *                                and trimming initial arguments, if any.)
 
189
 */
 
190
 
 
191
/*
 
192
 *    MathJax.Callback.After([...],cb1,cb2,...)
 
193
 *                             -- make a callback that isn't called until all the other
 
194
 *                                ones are called first.  I.e., wait for a union of
 
195
 *                                callbacks to occur before making the given callback.
 
196
 */
 
197
 
 
198
/*
 
199
 *  MathJax.Callback.Queue([callback,...])
 
200
 *                             -- make a synchronized queue of commands that process
 
201
 *                                sequentially, waiting for those that return uncalled
 
202
 *                                callbacks.
 
203
 */
 
204
 
 
205
/*
 
206
 *  MathJax.Callback.Signal(name)
 
207
 *                             -- finds or creates a names signal, to which listeners
 
208
 *                                can be attached and are signaled by messages posted
 
209
 *                                to the signal.  Responses can be asynchronous.
 
210
 */
 
211
 
 
212
(function (BASENAME) {
 
213
  var BASE = window[BASENAME];
 
214
  if (!BASE) {BASE = window[BASENAME] = {}}
 
215
  //
 
216
  //  Create a callback from an associative array
 
217
  //
 
218
  var CALLBACK = function (data) {
 
219
    var cb = new Function("return arguments.callee.execute.apply(arguments.callee,arguments)");
 
220
    for (var id in CALLBACK.prototype) {
 
221
      if (CALLBACK.prototype.hasOwnProperty(id)) {
 
222
        if (typeof(data[id]) !== 'undefined') {cb[id] = data[id]}
 
223
                                         else {cb[id] = CALLBACK.prototype[id]}
 
224
      }
 
225
    }
 
226
    cb.toString = CALLBACK.prototype.toString;
 
227
    return cb;
 
228
  };
 
229
  CALLBACK.prototype = {
 
230
    isCallback: true,
 
231
    hook: function () {},
 
232
    data: [],
 
233
    object: window,
 
234
    execute: function () {
 
235
      if (!this.called || this.autoReset) {
 
236
        this.called = !this.autoReset;
 
237
        return this.hook.apply(this.object,this.data.concat([].slice.call(arguments,0)));
 
238
      }
 
239
    },
 
240
    reset: function () {delete this.called},
 
241
    toString: function () {return this.hook.toString.apply(this.hook,arguments)}
 
242
  };
 
243
  var ISCALLBACK = function (f) {
 
244
    return (typeof(f) === "function" && f.isCallback);
 
245
  }
 
246
  //
 
247
  //  Evaluate a string in global context
 
248
  //
 
249
  var EVAL = function (code) {return eval.call(window,code)}
 
250
  EVAL("var __TeSt_VaR__ = 1"); // check if it works in global context
 
251
  if (window.__TeSt_VaR__) {
 
252
    try { delete window.__TeSt_VaR__; } // NOTE IE9 throws when in IE7 mode
 
253
    catch (error) { window.__TeSt_VaR__ = null; } 
 
254
  } else {
 
255
    if (window.execScript) {
 
256
      // IE
 
257
      EVAL = function (code) {
 
258
        BASE.__code = code;
 
259
        code = "try {"+BASENAME+".__result = eval("+BASENAME+".__code)} catch(err) {"+BASENAME+".__result = err}";
 
260
        window.execScript(code);
 
261
        var result = BASE.__result; delete BASE.__result; delete BASE.__code;
 
262
        if (result instanceof Error) {throw result}
 
263
        return result;
 
264
      }
 
265
    } else {
 
266
      // Safari2
 
267
      EVAL = function (code) {
 
268
        BASE.__code = code;
 
269
        code = "try {"+BASENAME+".__result = eval("+BASENAME+".__code)} catch(err) {"+BASENAME+".__result = err}";
 
270
        var head = (document.getElementsByTagName("head"))[0]; if (!head) {head = document.body}
 
271
        var script = document.createElement("script");
 
272
        script.appendChild(document.createTextNode(code));
 
273
        head.appendChild(script); head.removeChild(script);
 
274
        var result = BASE.__result; delete BASE.__result; delete BASE.__code;
 
275
        if (result instanceof Error) {throw result}
 
276
        return result;
 
277
      }
 
278
    }
 
279
  }
 
280
  //
 
281
  //  Create a callback from various types of data
 
282
  //
 
283
  var USING = function (args,i) {
 
284
    if (arguments.length > 1) {
 
285
      if (arguments.length === 2 && !(typeof arguments[0] === 'function') &&
 
286
          arguments[0] instanceof Object && typeof arguments[1] === 'number')
 
287
            {args = [].slice.call(args,i)}
 
288
      else {args = [].slice.call(arguments,0)}
 
289
    }
 
290
    if (args instanceof Array && args.length === 1) {args = args[0]}
 
291
    if (typeof args === 'function') {
 
292
      if (args.execute === CALLBACK.prototype.execute) {return args}
 
293
      return CALLBACK({hook: args});
 
294
    } else if (args instanceof Array) {
 
295
      if (typeof(args[0]) === 'string' && args[1] instanceof Object &&
 
296
                 typeof args[1][args[0]] === 'function') {
 
297
        return CALLBACK({hook: args[1][args[0]], object: args[1], data: args.slice(2)});
 
298
      } else if (typeof args[0] === 'function') {
 
299
        return CALLBACK({hook: args[0], data: args.slice(1)});
 
300
      } else if (typeof args[1] === 'function') {
 
301
        return CALLBACK({hook: args[1], object: args[0], data: args.slice(2)});
 
302
      }
 
303
    } else if (typeof(args) === 'string') {
 
304
      return CALLBACK({hook: EVAL, data: [args]});
 
305
    } else if (args instanceof Object) {
 
306
      return CALLBACK(args);
 
307
    } else if (typeof(args) === 'undefined') {
 
308
      return CALLBACK({});
 
309
    }
 
310
    throw Error("Can't make callback from given data");
 
311
  };
 
312
  
 
313
  //
 
314
  //  Wait for a given time to elapse and then perform the callback
 
315
  //
 
316
  var DELAY = function (time,callback) {
 
317
    callback = USING(callback);
 
318
    callback.timeout = setTimeout(callback,time);
 
319
    return callback;
 
320
  };
 
321
 
 
322
  //
 
323
  //  Callback used by AFTER, QUEUE, and SIGNAL to check if calls have completed
 
324
  //
 
325
  var WAITFOR = function (callback,signal) {
 
326
    callback = USING(callback);
 
327
    if (!callback.called) {WAITSIGNAL(callback,signal); signal.pending++}
 
328
  };
 
329
  var WAITEXECUTE = function () {
 
330
    var signals = this.signal; delete this.signal;
 
331
    this.execute = this.oldExecute; delete this.oldExecute;
 
332
    var result = this.execute.apply(this,arguments);
 
333
    if (ISCALLBACK(result) && !result.called) {WAITSIGNAL(result,signals)} else {
 
334
      for (var i = 0, m = signals.length; i < m; i++) {
 
335
        signals[i].pending--;
 
336
        if (signals[i].pending <= 0) {signals[i].call()}
 
337
      }
 
338
    }
 
339
  };
 
340
  var WAITSIGNAL = function (callback,signals) {
 
341
    if (!(signals instanceof Array)) {signals = [signals]}
 
342
    if (!callback.signal) {
 
343
      callback.oldExecute = callback.execute;
 
344
      callback.execute = WAITEXECUTE;
 
345
      callback.signal = signals;
 
346
    } else if (signals.length === 1) {callback.signal.push(signals[0])}
 
347
      else {callback.signal = callback.signal.concat(signals)}
 
348
  };
 
349
 
 
350
  //
 
351
  //  Create a callback that is called when a collection of other callbacks have
 
352
  //  all been executed.  If the callback gets called immediately (i.e., the
 
353
  //  others are all already called), check if it returns another callback
 
354
  //  and return that instead.
 
355
  //
 
356
  var AFTER = function (callback) {
 
357
    callback = USING(callback);
 
358
    callback.pending = 0;
 
359
    for (var i = 1, m = arguments.length; i < m; i++)
 
360
      {if (arguments[i]) {WAITFOR(arguments[i],callback)}}
 
361
    if (callback.pending === 0) {
 
362
      var result = callback();
 
363
      if (ISCALLBACK(result)) {callback = result}
 
364
    }
 
365
    return callback;
 
366
  };
 
367
 
 
368
  //
 
369
  //  An array of prioritized hooks that are executed sequentially
 
370
  //  with a given set of data.
 
371
  //
 
372
  var HOOKS = MathJax.Object.Subclass({
 
373
    //
 
374
    //  Initialize the array and the auto-reset status
 
375
    //
 
376
    Init: function (reset) {
 
377
      this.hooks = [];
 
378
      this.reset = reset;
 
379
    },
 
380
    //
 
381
    //  Add a callback to the list, in priority order (default priority is 10)
 
382
    //
 
383
    Add: function (hook,priority) {
 
384
      if (priority == null) {priority = 10}
 
385
      if (!ISCALLBACK(hook)) {hook = USING(hook)}
 
386
      hook.priority = priority;
 
387
      var i = this.hooks.length;
 
388
      while (i > 0 && priority < this.hooks[i-1].priority) {i--}
 
389
      this.hooks.splice(i,0,hook);
 
390
      return hook;
 
391
    },
 
392
    Remove: function (hook) {
 
393
      for (var i = 0, m = this.hooks.length; i < m; i++) {
 
394
        if (this.hooks[i] === hook) {this.hooks.splice(i,1); return}
 
395
      }
 
396
    },
 
397
    //
 
398
    //  Execute the list of callbacks, resetting them if requested.
 
399
    //  If any return callbacks, return a callback that will be 
 
400
    //  executed when they all have completed.
 
401
    //
 
402
    Execute: function () {
 
403
      var callbacks = [{}];
 
404
      for (var i = 0, m = this.hooks.length; i < m; i++) {
 
405
        if (this.reset) {this.hooks[i].reset()}
 
406
        var result = this.hooks[i].apply(window,arguments);
 
407
        if (ISCALLBACK(result) && !result.called) {callbacks.push(result)}
 
408
      }
 
409
      if (callbacks.length === 1) {return null}
 
410
      if (callbacks.length === 2) {return callbacks[1]}
 
411
      return AFTER.apply({},callbacks);
 
412
    }
 
413
  });
 
414
  
 
415
  //
 
416
  //  Run an array of callbacks passing them the given data.
 
417
  //  (Legacy function, since this has been replaced by the HOOKS object).
 
418
  //
 
419
  var EXECUTEHOOKS = function (hooks,data,reset) {
 
420
    if (!hooks) {return null}
 
421
    if (!(hooks instanceof Array)) {hooks = [hooks]}
 
422
    if (!(data instanceof Array))  {data = (data == null ? [] : [data])}
 
423
    var handler = HOOKS(reset);
 
424
    for (var i = 0, m = hooks.length; i < m; i++) {handler.Add(hooks[i])}
 
425
    return handler.Execute.apply(handler,data);
 
426
  };
 
427
   
 
428
  //
 
429
  //  Command queue that performs commands in order, waiting when
 
430
  //  necessary for commands to complete asynchronousely
 
431
  //
 
432
  var QUEUE = BASE.Object.Subclass({
 
433
    //
 
434
    //  Create the queue and push any commands that are specified
 
435
    //
 
436
    Init: function () {
 
437
      this.pending = 0; this.running = 0;
 
438
      this.queue = [];
 
439
      this.Push.apply(this,arguments);
 
440
    },
 
441
    //
 
442
    //  Add commands to the queue and run them. Adding a callback object
 
443
    //  (rather than a callback specification) queues a wait for that callback.
 
444
    //  Return the final callback for synchronization purposes.
 
445
    //
 
446
    Push: function () {
 
447
      var callback;
 
448
      for (var i = 0, m = arguments.length; i < m; i++) {
 
449
        callback = USING(arguments[i]);
 
450
        if (callback === arguments[i] && !callback.called)
 
451
          {callback = USING(["wait",this,callback])}
 
452
        this.queue.push(callback);
 
453
      }
 
454
      if (!this.running && !this.pending) {this.Process()}
 
455
      return callback;
 
456
    },
 
457
    //
 
458
    //  Process the command queue if we aren't waiting on another command
 
459
    //
 
460
    Process: function (queue) {
 
461
      while (!this.running && !this.pending && this.queue.length) {
 
462
        var callback = this.queue[0];
 
463
        queue = this.queue.slice(1); this.queue = [];
 
464
        this.Suspend(); var result = callback(); this.Resume();
 
465
        if (queue.length) {this.queue = queue.concat(this.queue)}
 
466
        if (ISCALLBACK(result) && !result.called) {WAITFOR(result,this)}
 
467
      }
 
468
    },
 
469
    //
 
470
    //  Suspend/Resume command processing on this queue
 
471
    //
 
472
    Suspend: function () {this.running++},
 
473
    Resume: function () {if (this.running) {this.running--}},
 
474
    //
 
475
    //  Used by WAITFOR to restart the queue when an action completes
 
476
    //
 
477
    call: function () {this.Process.apply(this,arguments)},
 
478
    wait: function (callback) {return callback}
 
479
  });
 
480
  
 
481
  //
 
482
  //  Create a named signal that listeners can attach to, to be signaled by
 
483
  //  postings made to the signal.  Posts are queued if they occur while one
 
484
  //  is already in process.
 
485
  //
 
486
  var SIGNAL = QUEUE.Subclass({
 
487
    Init: function (name) {
 
488
      QUEUE.prototype.Init.call(this);
 
489
      this.name = name;
 
490
      this.posted = [];              // the messages posted so far
 
491
      this.listeners = HOOKS(true);  // those with interest in this signal
 
492
    },
 
493
    //
 
494
    // Post a message to the signal listeners, with callback for when complete
 
495
    //
 
496
    Post: function (message,callback,forget) {
 
497
      callback = USING(callback);
 
498
      if (this.posting || this.pending) {
 
499
        this.Push(["Post",this,message,callback,forget]);
 
500
      } else {
 
501
        this.callback = callback; callback.reset();
 
502
        if (!forget) {this.posted.push(message)}
 
503
        this.Suspend(); this.posting = true;
 
504
        var result = this.listeners.Execute(message);
 
505
        if (ISCALLBACK(result) && !result.called) {WAITFOR(result,this)}
 
506
        this.Resume(); delete this.posting;
 
507
        if (!this.pending) {this.call()}
 
508
      }
 
509
      return callback;
 
510
    },
 
511
    //
 
512
    //  Clear the post history (so new listeners won't get old messages)
 
513
    //
 
514
    Clear: function (callback) {
 
515
      callback = USING(callback);
 
516
      if (this.posting || this.pending) {
 
517
        callback = this.Push(["Clear",this,callback]);
 
518
      } else {
 
519
        this.posted = [];
 
520
        callback();
 
521
      }
 
522
      return callback;
 
523
    },
 
524
    //
 
525
    //  Call the callback (all replies are in) and process the command queue
 
526
    //
 
527
    call: function () {this.callback(this); this.Process()},
 
528
    
 
529
    //
 
530
    //  A listener calls this to register intrest in the signal (so it will be called
 
531
    //  when posts occur).  If ignorePast is true, it will not be sent the post history.
 
532
    //
 
533
    Interest: function (callback,ignorePast,priority) {
 
534
      callback = USING(callback);
 
535
      this.listeners.Add(callback,priority);
 
536
      if (!ignorePast) {
 
537
        for (var i = 0, m = this.posted.length; i < m; i++) {
 
538
          callback.reset();
 
539
          var result = callback(this.posted[i]);
 
540
          if (ISCALLBACK(result) && i === this.posted.length-1) {WAITFOR(result,this)}
 
541
        }
 
542
      }
 
543
      return callback;
 
544
    },
 
545
    //
 
546
    //  A listener calls this to remove itself from a signal
 
547
    //
 
548
    NoInterest: function (callback) {
 
549
      this.listeners.Remove(callback);
 
550
    },
 
551
    
 
552
    //
 
553
    //  Hook a callback to a particular message on this signal
 
554
    //
 
555
    MessageHook: function (msg,callback,priority) {
 
556
      callback = USING(callback);
 
557
      if (!this.hooks) {this.hooks = {}; this.Interest(["ExecuteHooks",this])}
 
558
      if (!this.hooks[msg]) {this.hooks[msg] = HOOKS(true)}
 
559
      this.hooks[msg].Add(callback,priority);
 
560
      for (var i = 0, m = this.posted.length; i < m; i++)
 
561
        {if (this.posted[i] == msg) {callback.reset(); callback(this.posted[i])}}
 
562
      return callback;
 
563
    },
 
564
    //
 
565
    //  Execute the message hooks for the given message
 
566
    //
 
567
    ExecuteHooks: function (msg,more) {
 
568
      var type = ((msg instanceof Array) ? msg[0] : msg);
 
569
      if (!this.hooks[type]) {return null}
 
570
      return this.hooks[type].Execute(msg);
 
571
    }
 
572
    
 
573
  },{
 
574
    signals: {},  // the named signals
 
575
    find: function (name) {
 
576
      if (!SIGNAL.signals[name]) {SIGNAL.signals[name] = new SIGNAL(name)}
 
577
      return SIGNAL.signals[name];
 
578
    }
 
579
  });
 
580
  
 
581
  //
 
582
  //  The main entry-points
 
583
  //
 
584
  BASE.Callback = BASE.CallBack = USING;
 
585
  BASE.Callback.Delay = DELAY;
 
586
  BASE.Callback.After = AFTER;
 
587
  BASE.Callback.Queue = QUEUE;
 
588
  BASE.Callback.Signal = SIGNAL.find;
 
589
  BASE.Callback.Hooks = HOOKS;
 
590
  BASE.Callback.ExecuteHooks = EXECUTEHOOKS;
 
591
})("MathJax");
 
592
 
 
593
 
 
594
/**********************************************************/
 
595
 
 
596
(function (BASENAME) {
 
597
  var BASE = window[BASENAME];
 
598
  if (!BASE) {BASE = window[BASENAME] = {}}
 
599
  
 
600
  var isSafari2 = (navigator.vendor === "Apple Computer, Inc." &&
 
601
                   typeof navigator.vendorSub === "undefined");
 
602
  var sheets = 0; // used by Safari2
 
603
 
 
604
  //
 
605
  //  Update sheets count and look up the head object
 
606
  //  
 
607
  var HEAD = function (head) {
 
608
    if (document.styleSheets && document.styleSheets.length > sheets)
 
609
      {sheets = document.styleSheets.length}
 
610
    if (!head) {
 
611
      head = (document.getElementsByTagName("head"))[0];
 
612
      if (!head) {head = document.body}
 
613
    }
 
614
    return head;
 
615
  };
 
616
  
 
617
  //
 
618
  //  Remove scripts that are completed so they don't clutter up the HEAD.
 
619
  //  This runs via setTimeout since IE7 can't remove the script while it is running.
 
620
  //
 
621
  var SCRIPTS = [];  // stores scripts to be removed after a delay
 
622
  var REMOVESCRIPTS = function () {
 
623
    for (var i = 0, m = SCRIPTS.length; i < m; i++) {BASE.Ajax.head.removeChild(SCRIPTS[i])}
 
624
    SCRIPTS = [];
 
625
  };
 
626
  
 
627
  BASE.Ajax = {
 
628
    loaded: {},         // files already loaded
 
629
    loading: {},        // files currently in process of loading
 
630
    loadHooks: {},      // hooks to call when files are loaded
 
631
    timeout: 15*1000,   // timeout for loading of files (15 seconds)
 
632
    styleDelay: 1,      // delay to use before styles are available
 
633
    config: {root: ""}, // URL of root directory to load from
 
634
 
 
635
    STATUS: {
 
636
      OK: 1,         // file is loading or did load OK
 
637
      ERROR: -1      // file timed out during load
 
638
    },
 
639
    
 
640
    rootPattern: new RegExp("^\\["+BASENAME+"\\]"),
 
641
    
 
642
    //
 
643
    //  Return a complete URL to a file (replacing the root pattern)
 
644
    //
 
645
    fileURL: function (file) {return file.replace(this.rootPattern,this.config.root)},
 
646
    
 
647
    //
 
648
    //  Load a file if it hasn't been already.
 
649
    //  Make sure the file URL is "safe"?
 
650
    //
 
651
    Require: function (file,callback) {
 
652
      callback = BASE.Callback(callback); var type;
 
653
      if (file instanceof Object) {for (var i in file) {}; type = i.toUpperCase(); file = file[i]}
 
654
        else {type = file.split(/\./).pop().toUpperCase()}
 
655
      file = this.fileURL(file);
 
656
      // FIXME: check that URL is OK
 
657
      if (this.loaded[file]) {
 
658
        callback(this.loaded[file]);
 
659
      } else {
 
660
        var FILE = {}; FILE[type] = file;
 
661
        this.Load(FILE,callback);
 
662
      }
 
663
      return callback;
 
664
    },
 
665
 
 
666
    //
 
667
    //  Load a file regardless of where it is and whether it has
 
668
    //  already been loaded.
 
669
    //
 
670
    Load: function (file,callback) {
 
671
      callback = BASE.Callback(callback); var type;
 
672
      if (file instanceof Object) {for (var i in file) {}; type = i.toUpperCase(); file = file[i]}
 
673
        else {type = file.split(/\./).pop().toUpperCase()}
 
674
      file = this.fileURL(file);
 
675
      if (this.loading[file]) {
 
676
        this.addHook(file,callback);
 
677
      } else {
 
678
        this.head = HEAD(this.head);
 
679
        if (this.loader[type]) {this.loader[type].call(this,file,callback)}
 
680
         else {throw Error("Can't load files of type "+type)}
 
681
      }
 
682
      return callback;
 
683
    },
 
684
    
 
685
    //
 
686
    //  Register a load hook for a particular file (it will be called when
 
687
    //  loadComplete() is called for that file)
 
688
    //
 
689
    LoadHook: function (file,callback,priority) {
 
690
      callback = BASE.Callback(callback);
 
691
      if (file instanceof Object) {for (var i in file) {file = file[i]}}
 
692
      file = this.fileURL(file);
 
693
      if (this.loaded[file]) {callback(this.loaded[file])}
 
694
        else {this.addHook(file,callback,priority)}
 
695
      return callback;
 
696
    },
 
697
    addHook: function (file,callback,priority) {
 
698
      if (!this.loadHooks[file]) {this.loadHooks[file] = MathJax.Callback.Hooks()}
 
699
      this.loadHooks[file].Add(callback,priority);
 
700
    },
 
701
    
 
702
    //
 
703
    //  Used when files are combined in a preloading configuration file
 
704
    //
 
705
    Preloading: function () {
 
706
      for (var i = 0, m = arguments.length; i < m; i++) {
 
707
        var file = this.fileURL(arguments[i]);
 
708
        if (!this.loading[file]) {this.loading[file] = {preloaded: true}}
 
709
      }
 
710
    },
 
711
    
 
712
    //
 
713
    //  Code used to load the various types of files
 
714
    //  (JS for JavaScript, CSS for style sheets)
 
715
    //
 
716
    loader: {
 
717
      //
 
718
      //  Create a SCRIPT tag to load the file
 
719
      //
 
720
      JS: function (file,callback) {
 
721
        var script = document.createElement("script");
 
722
        var timeout = BASE.Callback(["loadTimeout",this,file]);
 
723
        this.loading[file] = {
 
724
          callback: callback,
 
725
          message: BASE.Message.File(file),
 
726
          timeout: setTimeout(timeout,this.timeout),
 
727
          status: this.STATUS.OK,
 
728
          script: script
 
729
        };
 
730
        script.onerror = timeout;  // doesn't work in IE and no apparent substitute
 
731
        script.type = "text/javascript";
 
732
        script.src = file;
 
733
        this.head.appendChild(script);
 
734
      },
 
735
      //
 
736
      //  Create a LINK tag to load the style sheet
 
737
      //
 
738
      CSS: function (file,callback) {
 
739
        var link = document.createElement("link");
 
740
        link.rel = "stylesheet"; link.type = "text/css"; link.href = file;
 
741
        this.loading[file] = {
 
742
          callback: callback,
 
743
          message: BASE.Message.File(file),
 
744
          status: this.STATUS.OK
 
745
        };
 
746
        this.head.appendChild(link);
 
747
        this.timer.create.call(this,[this.timer.file,file],link);
 
748
      }
 
749
    },
 
750
    
 
751
    //
 
752
    //  Timing code for checking when style sheets are available.
 
753
    //
 
754
    timer: {
 
755
      //
 
756
      //  Create the timing callback and start the timing loop.
 
757
      //  We use a delay because some browsers need it to allow the styles
 
758
      //  to be processed.
 
759
      //
 
760
      create: function (callback,node) {
 
761
        callback = BASE.Callback(callback);
 
762
        if (node.nodeName === "STYLE" && node.styleSheet &&
 
763
            typeof(node.styleSheet.cssText) !== 'undefined') {
 
764
          callback(this.STATUS.OK); // MSIE processes style immediately, but doesn't set its styleSheet!
 
765
        } else if (window.chrome && typeof(window.sessionStorage) !== "undefined" &&
 
766
                   node.nodeName === "STYLE") {
 
767
          callback(this.STATUS.OK); // Same for Chrome 5 (beta), Grrr.
 
768
        } else if (isSafari2) {
 
769
          this.timer.start(this,[this.timer.checkSafari2,sheets++,callback],this.styleDelay);
 
770
        } else {
 
771
          this.timer.start(this,[this.timer.checkLength,node,callback],this.styleDelay);
 
772
        }
 
773
        return callback;
 
774
      },
 
775
      //
 
776
      //  Start the timer for the given callback checker
 
777
      //
 
778
      start: function (AJAX,check,delay,timeout) {
 
779
        check = BASE.Callback(check);
 
780
        check.execute = this.execute; check.time = this.time;
 
781
        check.STATUS = AJAX.STATUS; check.timeout = timeout || AJAX.timeout;
 
782
        check.delay = check.total = 0;
 
783
        if (delay) {setTimeout(check,delay)} else {check()}
 
784
      },
 
785
      //
 
786
      //  Increment the time total, increase the delay
 
787
      //  and test if we are past the timeout time.
 
788
      //  
 
789
      time: function (callback) {
 
790
        this.total += this.delay;
 
791
        this.delay = Math.floor(this.delay * 1.05 + 5);
 
792
        if (this.total >= this.timeout) {callback(this.STATUS.ERROR); return 1}
 
793
        return 0;
 
794
      },
 
795
      //
 
796
      //  For JS file loads, call the proper routine according to status
 
797
      //
 
798
      file: function (file,status) {
 
799
        if (status < 0) {BASE.Ajax.loadTimeout(file)} else {BASE.Ajax.loadComplete(file)}
 
800
      },
 
801
      //
 
802
      //  Call the hook with the required data
 
803
      //
 
804
      execute: function () {this.hook.call(this.object,this,this.data[0],this.data[1])},
 
805
      //
 
806
      //  Safari2 doesn't set the link's stylesheet, so we need to look in the
 
807
      //  document.styleSheets array for the new sheet when it is created
 
808
      //
 
809
      checkSafari2: function (check,length,callback) {
 
810
        if (check.time(callback)) return;
 
811
        if (document.styleSheets.length > length &&
 
812
            document.styleSheets[length].cssRules &&
 
813
            document.styleSheets[length].cssRules.length)
 
814
          {callback(check.STATUS.OK)} else {setTimeout(check,check.delay)}
 
815
      },
 
816
      //
 
817
      //  Look for the stylesheets rules and check when they are defined
 
818
      //  and no longer of length zero.  (This assumes there actually ARE
 
819
      //  some rules in the stylesheet.)
 
820
      //  
 
821
      checkLength: function (check,node,callback) {
 
822
        if (check.time(callback)) return;
 
823
        var isStyle = 0; var sheet = (node.sheet || node.styleSheet);
 
824
        try {if ((sheet.cssRules||sheet.rules||[]).length > 0) {isStyle = 1}} catch(err) {
 
825
          if (err.message.match(/protected variable|restricted URI/)) {isStyle = 1}
 
826
          else if (err.message.match(/Security error/)) {
 
827
            // Firefox3 gives "Security error" for missing files, so
 
828
            //   can't distinguish that from OK files on remote servers.
 
829
            //   or OK files in different directory from local files.
 
830
            isStyle = 1; // just say it is OK (can't really tell)
 
831
          }
 
832
        }
 
833
        if (isStyle) {
 
834
          // Opera 9.6 requires this setTimeout
 
835
          setTimeout(BASE.Callback([callback,check.STATUS.OK]),0);
 
836
        } else {
 
837
          setTimeout(check,check.delay);
 
838
        }
 
839
      }
 
840
    },
 
841
 
 
842
    //
 
843
    //  JavaScript code must call this when they are completely initialized
 
844
    //  (this allows them to perform asynchronous actions before indicating
 
845
    //  that they are complete).
 
846
    //
 
847
    loadComplete: function (file) {
 
848
      file = this.fileURL(file);
 
849
      var loading = this.loading[file];
 
850
      if (loading && !loading.preloaded) {
 
851
        BASE.Message.Clear(loading.message);
 
852
        clearTimeout(loading.timeout);
 
853
        if (loading.script) {
 
854
          if (SCRIPTS.length === 0) {setTimeout(REMOVESCRIPTS,0)}
 
855
          SCRIPTS.push(loading.script);
 
856
        }
 
857
        this.loaded[file] = loading.status; delete this.loading[file];
 
858
        this.addHook(file,loading.callback);
 
859
      } else {
 
860
        if (loading) {delete this.loading[file]}
 
861
        this.loaded[file] = this.STATUS.OK;
 
862
        loading = {status: this.STATUS.OK}
 
863
      }
 
864
      if (!this.loadHooks[file]) {return null}
 
865
      return this.loadHooks[file].Execute(loading.status);
 
866
    },
 
867
    
 
868
    //
 
869
    //  If a file fails to load within the timeout period (or the onerror handler
 
870
    //  is called), this routine runs to signal the error condition.
 
871
    //  
 
872
    loadTimeout: function (file) {
 
873
      if (this.loading[file].timeout) {clearTimeout(this.loading[file].timeout)}
 
874
      this.loading[file].status = this.STATUS.ERROR;
 
875
      this.loadError(file);
 
876
      this.loadComplete(file);
 
877
    },
 
878
    
 
879
    //
 
880
    //  The default error hook for file load failures
 
881
    //
 
882
    loadError: function (file) {
 
883
      BASE.Message.Set("File failed to load: "+file,null,2000);
 
884
      BASE.Hub.signal.Post(["file load error",file]);
 
885
    },
 
886
 
 
887
    //
 
888
    //  Defines a style sheet from a hash of style declarations (key:value pairs
 
889
    //  where the key is the style selector and the value is a hash of CSS attributes 
 
890
    //  and values).
 
891
    //
 
892
    Styles: function (styles,callback) {
 
893
      var styleString = this.StyleString(styles);
 
894
      if (styleString === "") {
 
895
        callback = BASE.Callback(callback);
 
896
        callback();
 
897
      } else {
 
898
        var style = document.createElement("style"); style.type = "text/css";
 
899
        this.head = HEAD(this.head);
 
900
        this.head.appendChild(style);
 
901
        if (style.styleSheet && typeof(style.styleSheet.cssText) !== 'undefined') {
 
902
          style.styleSheet.cssText = styleString;
 
903
        } else {
 
904
          style.appendChild(document.createTextNode(styleString));
 
905
        }
 
906
        callback = this.timer.create.call(this,callback,style);
 
907
      }
 
908
      return callback;
 
909
    },
 
910
    
 
911
    //
 
912
    //  Create a stylesheet string from a style declaration object
 
913
    //
 
914
    StyleString: function (styles) {
 
915
      if (typeof(styles) === 'string') {return styles}
 
916
      var string = "", id, style;
 
917
      for (id in styles) {if (styles.hasOwnProperty(id)) {
 
918
        if (typeof styles[id] === 'string') {
 
919
          string += id + " {"+styles[id]+"}\n";
 
920
        } else if (styles[id] instanceof Array) {
 
921
          for (var i = 0; i < styles[id].length; i++) {
 
922
            style = {}; style[id] = styles[id][i];
 
923
            string += this.StyleString(style);
 
924
          }
 
925
        } else if (id.substr(0,6) === '@media') {
 
926
          string += id + " {"+this.StyleString(styles[id])+"}\n";
 
927
        } else if (styles[id] != null) {
 
928
          style = [];
 
929
          for (var name in styles[id]) {if (styles[id].hasOwnProperty(name)) {
 
930
            if (styles[id][name] != null) 
 
931
              {style[style.length] = name + ': ' + styles[id][name]}
 
932
          }}
 
933
          string += id +" {"+style.join('; ')+"}\n";
 
934
        }
 
935
      }}
 
936
      return string;
 
937
    }
 
938
  };
 
939
 
 
940
})("MathJax");
 
941
 
 
942
/**********************************************************/
 
943
 
 
944
MathJax.HTML = {
 
945
  //
 
946
  //  Create an HTML element with given attributes and content.
 
947
  //  The def parameter is an (optional) object containing key:value pairs
 
948
  //  of the attributes and their values, and contents is an (optional)
 
949
  //  array of strings to be inserted as text, or arrays of the form
 
950
  //  [type,def,contents] that describes an HTML element to be inserted
 
951
  //  into the current element.  Thus the contents can describe a complete
 
952
  //  HTML snippet of arbitrary complexity.  E.g.:
 
953
  //  
 
954
  //    MathJax.HTML.Element("span",{id:"mySpan",style{"font-style":"italic"}},[
 
955
  //        "(See the ",["a",{href:"http://www.mathjax.org"},["MathJax home page"]],
 
956
  //        " for more details.)"]);
 
957
  // 
 
958
  Element: function (type,def,contents) {
 
959
    var obj = document.createElement(type);
 
960
    if (def) {
 
961
      if (def.style) {
 
962
        var style = def.style; def.style = {};
 
963
        for (var id in style) {if (style.hasOwnProperty(id))
 
964
          {def.style[id.replace(/-([a-z])/g,this.ucMatch)] = style[id]}}
 
965
      }
 
966
      MathJax.Hub.Insert(obj,def);
 
967
    }
 
968
    if (contents) {
 
969
      if (!(contents instanceof Array)) {contents = [contents]}
 
970
      for (var i = 0; i < contents.length; i++) {
 
971
        if (contents[i] instanceof Array) {
 
972
          obj.appendChild(this.Element(contents[i][0],contents[i][1],contents[i][2]));
 
973
        } else {
 
974
          obj.appendChild(document.createTextNode(contents[i]));
 
975
        }
 
976
      }
 
977
    }
 
978
    return obj;
 
979
  },
 
980
  ucMatch: function (match,c) {return c.toUpperCase()},
 
981
  addElement: function (span,type,def,contents) {return span.appendChild(this.Element(type,def,contents))},
 
982
  TextNode: function (text) {return document.createTextNode(text)},
 
983
  addText: function (span,text) {return span.appendChild(this.TextNode(text))},
 
984
 
 
985
  //
 
986
  //  Set and get the text of a script
 
987
  //
 
988
  setScript: function (script,text) {
 
989
    if (this.setScriptBug) {script.text = text} else {
 
990
      while (script.firstChild) {script.removeChild(script.firstChild)}
 
991
      this.addText(script,text);
 
992
    }
 
993
  },
 
994
  getScript: function (script) {
 
995
    var text = (script.text === "" ? script.innerHTML : script.text);
 
996
    return text.replace(/^\s+/,"").replace(/\s+$/,"");
 
997
  },
 
998
 
 
999
  //
 
1000
  //  Manage cookies
 
1001
  //
 
1002
  Cookie: {
 
1003
    prefix: "mjx",
 
1004
    expires: 365,
 
1005
    
 
1006
    //
 
1007
    //  Save an object as a named cookie
 
1008
    //
 
1009
    Set: function (name,def) {
 
1010
      var keys = [];
 
1011
      if (def) {
 
1012
        for (var id in def) {if (def.hasOwnProperty(id)) {
 
1013
          keys.push(id+":"+def[id].toString().replace(/&/g,"&&"));
 
1014
        }}
 
1015
      }
 
1016
      var cookie = this.prefix+"."+name+"="+escape(keys.join('&;'));
 
1017
      if (this.expires) {
 
1018
        var time = new Date(); time.setDate(time.getDate() + this.expires);
 
1019
        cookie += '; expires='+time.toGMTString();
 
1020
      }
 
1021
      document.cookie = cookie+"; path=/";
 
1022
    },
 
1023
    
 
1024
    //
 
1025
    //  Get the contents of a named cookie and incorporate
 
1026
    //  it into the given object (or return a fresh one)
 
1027
    //
 
1028
    Get: function (name,obj) {
 
1029
      if (!obj) {obj = {}}
 
1030
      var pattern = new RegExp("(?:^|;\\s*)"+this.prefix+"\\."+name+"=([^;]*)(?:;|$)");
 
1031
      var match = pattern.exec(document.cookie);
 
1032
      if (match && match[1] !== "") {
 
1033
        var keys = unescape(match[1]).split('&;');
 
1034
        for (var i = 0, m = keys.length; i < m; i++) {
 
1035
          match = keys[i].match(/([^:]+):(.*)/);
 
1036
          var value = match[2].replace(/&&/g,'&');
 
1037
          if (value === "true") {value = true} else if (value === "false") {value = false}
 
1038
            else if (value.match(/^-?(\d+(\.\d+)?|\.\d+)$/)) {value = parseFloat(value)}
 
1039
          obj[match[1]] = value;
 
1040
        }
 
1041
      }
 
1042
      return obj;
 
1043
    }
 
1044
  }
 
1045
    
 
1046
};
 
1047
 
 
1048
 
 
1049
/**********************************************************/
 
1050
 
 
1051
MathJax.Message = {
 
1052
  ready: false,  // used to tell when the styles are available
 
1053
  log: [{}], current: null,
 
1054
  textNodeBug: (navigator.vendor === "Apple Computer, Inc." &&
 
1055
                typeof navigator.vendorSub === "undefined") ||
 
1056
               (window.hasOwnProperty && window.hasOwnProperty("konqueror")), // Konqueror displays some gibberish with text.nodeValue = "..."
 
1057
  
 
1058
  styles: {
 
1059
    "#MathJax_Message": {
 
1060
      position: "fixed", left: "1px", bottom: "2px",
 
1061
      'background-color': "#E6E6E6",  border: "1px solid #959595",
 
1062
      margin: "0px", padding: "2px 8px",
 
1063
      'z-index': "102", color: "black", 'font-size': "80%",
 
1064
      width: "auto", 'white-space': "nowrap"
 
1065
    },
 
1066
    
 
1067
    "#MathJax_MSIE_Frame": {
 
1068
      position: "absolute",
 
1069
      top:0, left: 0, width: "0px", 'z-index': 101,
 
1070
      border: "0px", margin: "0px", padding: "0px"
 
1071
    }
 
1072
  },
 
1073
  
 
1074
  browsers: {
 
1075
    MSIE: function (browser) {
 
1076
      MathJax.Hub.config.styles["#MathJax_Message"].position = "absolute";
 
1077
      MathJax.Message.quirks = (document.compatMode === "BackCompat");
 
1078
    },
 
1079
    Chrome: function (browser) {
 
1080
      MathJax.Hub.config.styles["#MathJax_Message"].bottom = "1.5em";
 
1081
      MathJax.Hub.config.styles["#MathJax_Message"].left = "1em";
 
1082
    }
 
1083
  },
 
1084
  
 
1085
  Init: function (styles) {
 
1086
    if (styles) {this.ready = true}
 
1087
    if (!document.body || !this.ready) {return false}
 
1088
    //
 
1089
    //  ASCIIMathML replaces the entire page with a copy of itself (@#!#%@!!)
 
1090
    //  so check that this.div is still part of the page, otherwise look up
 
1091
    //  the copy and use that.
 
1092
    //
 
1093
    if (this.div && this.div.parentNode == null) {
 
1094
      this.div = document.getElementById("MathJax_Message");
 
1095
      if (this.div) {this.text = this.div.firstChild}
 
1096
    }
 
1097
    if (!this.div) {
 
1098
      var frame = document.body;
 
1099
      if (MathJax.Hub.Browser.isMSIE) {
 
1100
          frame = this.frame = this.addDiv(document.body); frame.removeAttribute("id");
 
1101
        frame.style.position = "absolute";
 
1102
        frame.style.border = frame.style.margin = frame.style.padding = "0px";
 
1103
        frame.style.zIndex = "101"; frame.style.height = "0px";
 
1104
        frame = this.addDiv(frame);
 
1105
        frame.id = "MathJax_MSIE_Frame";
 
1106
        window.attachEvent("onscroll",this.MoveFrame);
 
1107
        window.attachEvent("onresize",this.MoveFrame);
 
1108
        this.MoveFrame();
 
1109
      }
 
1110
      this.div = this.addDiv(frame); this.div.style.display = "none";
 
1111
      this.text = this.div.appendChild(document.createTextNode(""));
 
1112
    }
 
1113
    return true;
 
1114
  },
 
1115
  
 
1116
  addDiv: function (parent) {
 
1117
    var div = document.createElement("div");
 
1118
    div.id = "MathJax_Message";
 
1119
    if (parent.firstChild) {parent.insertBefore(div,parent.firstChild)}
 
1120
      else {parent.appendChild(div)}
 
1121
    return div;
 
1122
  },
 
1123
  
 
1124
  MoveFrame: function () {
 
1125
    var body = (MathJax.Message.quirks ? document.body : document.documentElement);
 
1126
    var frame = MathJax.Message.frame;
 
1127
    frame.style.left = body.scrollLeft + 'px';
 
1128
    frame.style.top = body.scrollTop + 'px';
 
1129
    frame.style.width = body.clientWidth + 'px';
 
1130
    frame = frame.firstChild;
 
1131
    frame.style.height = body.clientHeight + 'px';
 
1132
  },
 
1133
  
 
1134
  filterText: function (text,n) {
 
1135
    if (MathJax.Hub.config.messageStyle === "simple") {
 
1136
      if (text.match(/^Loading /)) {
 
1137
        if (!this.loading) {this.loading = "Loading "}
 
1138
        text = this.loading; this.loading += ".";
 
1139
      } else if (text.match(/^Processing /)) {
 
1140
        if (!this.processing) {this.processing = "Processing "}
 
1141
        text = this.processing; this.processing += ".";
 
1142
      } else if (text.match(/^Typesetting /)) {
 
1143
        if (!this.typesetting) {this.typesetting = "Typesetting "}
 
1144
        text = this.typesetting; this.typesetting += ".";
 
1145
      }
 
1146
    }
 
1147
    return text;
 
1148
  },
 
1149
  
 
1150
  Set: function (text,n,clearDelay) {
 
1151
    if (this.timer) {clearTimeout(this.timer); delete this.timeout}
 
1152
    if (n == null) {n = this.log.length; this.log[n] = {}}
 
1153
    this.log[n].text = text; this.log[n].filteredText = text = this.filterText(text,n);
 
1154
    if (typeof(this.log[n].next) === "undefined") {
 
1155
      this.log[n].next = this.current;
 
1156
      if (this.current != null) {this.log[this.current].prev = n}
 
1157
      this.current = n;
 
1158
    }
 
1159
    if (this.current === n && MathJax.Hub.config.messageStyle !== "none") {
 
1160
      if (this.Init()) {
 
1161
        if (this.textNodeBug) {this.div.innerHTML = text} else {this.text.nodeValue = text}
 
1162
        this.div.style.display = "";
 
1163
        if (this.status) {window.status = ""; delete this.status}
 
1164
      } else {
 
1165
        window.status = text;
 
1166
        this.status = true;
 
1167
      }
 
1168
    }
 
1169
    if (clearDelay) {setTimeout(MathJax.Callback(["Clear",this,n]),clearDelay)}
 
1170
    else if (clearDelay == 0) {this.Clear(n,0)}
 
1171
    return n;
 
1172
  },
 
1173
  
 
1174
  Clear: function (n,delay) {
 
1175
    if (this.log[n].prev != null) {this.log[this.log[n].prev].next = this.log[n].next}
 
1176
    if (this.log[n].next != null) {this.log[this.log[n].next].prev = this.log[n].prev}
 
1177
    if (this.current === n) {
 
1178
      this.current = this.log[n].next;
 
1179
      if (this.text) {
 
1180
        if (this.div.parentNode == null) {this.Init()} // see ASCIIMathML comments above
 
1181
        if (this.current == null) {
 
1182
        if (this.timer) {clearTimeout(this.timer); delete this.timer}
 
1183
          if (delay == null) {delay = 600}
 
1184
          if (delay === 0) {this.Remove()}
 
1185
            else {this.timer = setTimeout(MathJax.Callback(["Remove",this]),delay)}
 
1186
        } else if (MathJax.Hub.config.messageStyle !== "none") {
 
1187
          if (this.textNodeBug) {this.div.innerHTML = this.log[this.current].filteredText}
 
1188
                           else {this.text.nodeValue = this.log[this.current].filteredText}
 
1189
        }
 
1190
        if (this.status) {window.status = ""; delete this.status}
 
1191
      } else if (this.status) {
 
1192
        window.status = (this.current == null ? "" : this.log[this.current].text);
 
1193
      }
 
1194
    }
 
1195
    delete this.log[n].next; delete this.log[n].prev;
 
1196
    delete this.log[n].filteredText;
 
1197
  },
 
1198
  
 
1199
  Remove: function () {
 
1200
    // FIXME:  do a fade out or something else interesting?
 
1201
    this.text.nodeValue = "";
 
1202
    this.div.style.display = "none";
 
1203
  },
 
1204
  
 
1205
  File: function (file) {
 
1206
    var root = MathJax.Ajax.config.root;
 
1207
    if (file.substr(0,root.length) === root) {file = "[MathJax]"+file.substr(root.length)}
 
1208
    return this.Set("Loading "+file);
 
1209
  },
 
1210
  
 
1211
  Log: function () {
 
1212
    var strings = [];
 
1213
    for (var i = 1, m = this.log.length; i < m; i++) {strings[i] = this.log[i].text}
 
1214
    return strings.join("\n");
 
1215
  }
 
1216
 
 
1217
};
 
1218
 
 
1219
/**********************************************************/
 
1220
 
 
1221
MathJax.Hub = {
 
1222
  config: {
 
1223
    root: "",
 
1224
    config: [],      // list of configuration files to load
 
1225
    styleSheets: [], // list of CSS files to load
 
1226
    styles: {        // styles to generate in-line
 
1227
      ".MathJax_Preview": {color: "#888"}
 
1228
    },
 
1229
    jax: [],         // list of input and output jax to load
 
1230
    extensions: [],  // list of extensions to load
 
1231
    preJax: null,    // pattern to remove from before math script tag
 
1232
    postJax: null,   // pattern to remove from after math script tag
 
1233
    displayAlign: 'center',       // how to align displayed equations (left, center, right)
 
1234
    displayIndent: '0',           // indentation for displayed equations (when not centered)
 
1235
    preRemoveClass: 'MathJax_Preview', // class of objects to remove preceeding math script
 
1236
    showProcessingMessages: true, // display "Processing math: nn%" messages or not
 
1237
    messageStyle: "normal",       // set to "none" or "simple" (for "Loading..." and "Processing...")
 
1238
    delayStartupUntil: "none",    // set to "onload" to delay setup until the onload handler runs
 
1239
                                  // set to "configured" to delay startup until MathJax.Hub.Configured() is called
 
1240
                                  // set to a Callback to wait for before continuing with the startup
 
1241
    skipStartupTypeset: false,    // set to true to skip PreProcess and Process during startup
 
1242
    "v1.0-compatible": true,  // set to false to prevent message about configuration change
 
1243
    elements: [],             // array of elements to process when none is given explicitly
 
1244
    positionToHash: true,    // after initial typeset pass, position to #hash location?
 
1245
     
 
1246
    showMathMenu: true,      // attach math context menu to typeset math?
 
1247
    showMathMenuMSIE: true,  // separtely determine if MSIE should have math menu
 
1248
                             //  (since the code for that is a bit delicate)
 
1249
 
 
1250
    menuSettings: {
 
1251
      zoom: "None",        //  when to do MathZoom
 
1252
      CTRL: false,         //    require CTRL for MathZoom?
 
1253
      ALT: false,          //    require Alt or Option?
 
1254
      CMD: false,          //    require CMD?
 
1255
      Shift: false,        //    require Shift?
 
1256
      discoverable: false, //  make math menu discoverable on hover?
 
1257
      zscale: "200%",      //  the scaling factor for MathZoom
 
1258
      renderer: "",        //  set when Jax are loaded
 
1259
      font: "Auto",        //  what font HTML-CSS should use
 
1260
      context: "MathJax",  //  or "Browser" for pass-through to browser menu
 
1261
      mpContext: false,    //  true means pass menu events to MathPlayer in IE
 
1262
      mpMouse: false,      //  true means pass mouse events to MathPlayer in IE
 
1263
      texHints: true       //  include class names for TeXAtom elements
 
1264
    },
 
1265
    
 
1266
    errorSettings: {
 
1267
      message: ["[Math Processing Error]"], // HTML snippet structure for message to use
 
1268
      style: {color: "#CC0000", "font-style":"italic"}  // style for message
 
1269
    }
 
1270
  },
 
1271
  
 
1272
  preProcessors: MathJax.Callback.Hooks(true), // list of callbacks for preprocessing (initialized by extensions)
 
1273
  inputJax: {},          // mime-type mapped to input jax (by registration)
 
1274
  outputJax: {order:{}}, // mime-type mapped to output jax list (by registration)
 
1275
 
 
1276
  processUpdateTime: 250, // time between screen updates when processing math (milliseconds)
 
1277
  processUpdateDelay: 10, // pause between screen updates to allow other processing (milliseconds)
 
1278
 
 
1279
  signal: MathJax.Callback.Signal("Hub"), // Signal used for Hub events
 
1280
 
 
1281
  Config: function (def) {
 
1282
    this.Insert(this.config,def);
 
1283
    if (this.config.Augment) {this.Augment(this.config.Augment)}
 
1284
  },
 
1285
  CombineConfig: function (name,def) {
 
1286
    var config = this.config, id, parent; name = name.split(/\./);
 
1287
    for (var i = 0, m = name.length; i < m; i++) {
 
1288
      id = name[i]; if (!config[id]) {config[id] = {}}
 
1289
      parent = config; config = config[id];
 
1290
    }
 
1291
    parent[id] = config = this.Insert(def,config);
 
1292
    return config;
 
1293
  },
 
1294
  
 
1295
  Register: {
 
1296
    PreProcessor: function () {MathJax.Hub.preProcessors.Add.apply(MathJax.Hub.preProcessors,arguments)},
 
1297
    MessageHook: function () {return MathJax.Hub.signal.MessageHook.apply(MathJax.Hub.signal,arguments)},
 
1298
    StartupHook: function () {return MathJax.Hub.Startup.signal.MessageHook.apply(MathJax.Hub.Startup.signal,arguments)},
 
1299
    LoadHook: function () {return MathJax.Ajax.LoadHook.apply(MathJax.Ajax,arguments)}
 
1300
  },
 
1301
  
 
1302
  getAllJax: function (element) {
 
1303
    var jax = [], scripts = this.elementScripts(element);
 
1304
    for (var i = 0, m = scripts.length; i < m; i++) {
 
1305
      if (scripts[i].MathJax && scripts[i].MathJax.elementJax)
 
1306
        {jax.push(scripts[i].MathJax.elementJax)}
 
1307
    }
 
1308
    return jax;
 
1309
  },
 
1310
  
 
1311
  getJaxByType: function (type,element) {
 
1312
    var jax = [], scripts = this.elementScripts(element);
 
1313
    for (var i = 0, m = scripts.length; i < m; i++) {
 
1314
      if (scripts[i].MathJax && scripts[i].MathJax.elementJax &&
 
1315
          scripts[i].MathJax.elementJax.mimeType === type)
 
1316
            {jax.push(scripts[i].MathJax.elementJax)}
 
1317
    }
 
1318
    return jax;
 
1319
  },
 
1320
  
 
1321
  getJaxByInputType: function (type,element) {
 
1322
    var jax = [], scripts = this.elementScripts(element);
 
1323
    for (var i = 0, m = scripts.length; i < m; i++) {
 
1324
      if (scripts[i].MathJax && scripts[i].MathJax.elementJax &&
 
1325
          scripts[i].type && scripts[i].type.replace(/ *;(.|\s)*/,"") === type)
 
1326
        {jax.push(scripts[i].MathJax.elementJax)}
 
1327
    }
 
1328
    return jax;
 
1329
  },
 
1330
  
 
1331
  getJaxFor: function (element) {
 
1332
    if (typeof(element) === 'string') {element = document.getElementById(element)}
 
1333
    if (element && element.MathJax) {return element.MathJax.elementJax}
 
1334
    if (element && element.isMathJax) {
 
1335
      while (element && !element.jaxID) {element = element.parentNode}
 
1336
      if (element) {return MathJax.OutputJax[element.jaxID].getJaxFromMath(element)}
 
1337
    }
 
1338
    return null;
 
1339
  },
 
1340
  
 
1341
  isJax: function (element) {
 
1342
    if (typeof(element) === 'string') {element = document.getElementById(element)}
 
1343
    if (element && element.isMathJax) {return 1}
 
1344
    if (element && element.tagName != null && element.tagName.toLowerCase() === 'script') {
 
1345
      if (element.MathJax) 
 
1346
        {return (element.MathJax.state === MathJax.ElementJax.STATE.PROCESSED ? 1 : -1)}
 
1347
      if (element.type && this.inputJax[element.type.replace(/ *;(.|\s)*/,"")]) {return -1}
 
1348
    }
 
1349
    return 0;
 
1350
  },
 
1351
  
 
1352
  setRenderer: function (renderer,type) {
 
1353
    if (!renderer) return;
 
1354
    if (!MathJax.OutputJax[renderer]) {
 
1355
      this.config.menuSettings.renderer = "";
 
1356
      var file = "[MathJax]/jax/output/"+renderer+"/config.js";
 
1357
      return MathJax.Ajax.Require(file,["setRenderer",this,renderer,type]);
 
1358
    } else {
 
1359
      this.config.menuSettings.renderer = renderer;
 
1360
      if (type == null) {type = "jax/mml"}
 
1361
      var jax = this.outputJax;
 
1362
      if (jax[type] && jax[type].length) {
 
1363
        if (renderer !== jax[type][0].id) {
 
1364
          jax[type].unshift(MathJax.OutputJax[renderer]);
 
1365
          return this.signal.Post(["Renderer Selected",renderer]);
 
1366
        }
 
1367
      }
 
1368
      return null;
 
1369
    }
 
1370
  },
 
1371
 
 
1372
  Queue: function () {
 
1373
    return this.queue.Push.apply(this.queue,arguments);
 
1374
  },
 
1375
  
 
1376
  Typeset: function (element,callback) {
 
1377
    if (!MathJax.isReady) return null;
 
1378
    var ec = this.elementCallback(element,callback);
 
1379
    var queue = MathJax.Callback.Queue();
 
1380
    for (var i = 0, m = ec.elements.length; i < m; i++) {
 
1381
      if (ec.elements[i]) {
 
1382
        queue.Push(
 
1383
          ["PreProcess",this,ec.elements[i]],
 
1384
          ["Process",this,ec.elements[i]]
 
1385
        );
 
1386
      }
 
1387
    }
 
1388
    return queue.Push(ec.callback);
 
1389
  },
 
1390
  
 
1391
  PreProcess: function (element,callback) {
 
1392
    var ec = this.elementCallback(element,callback);
 
1393
    var queue = MathJax.Callback.Queue();
 
1394
    for (var i = 0, m = ec.elements.length; i < m; i++) {
 
1395
      if (ec.elements[i]) {
 
1396
        queue.Push(
 
1397
          ["Post",this.signal,["Begin PreProcess",ec.elements[i]]],
 
1398
          (arguments.callee.disabled? {} : ["Execute",this.preProcessors,ec.elements[i]]),
 
1399
          ["Post",this.signal,["End PreProcess",ec.elements[i]]]
 
1400
        );
 
1401
      }
 
1402
    }
 
1403
    return queue.Push(ec.callback);
 
1404
  },
 
1405
 
 
1406
  Process:   function (element,callback) {return this.takeAction("Process",element,callback)},
 
1407
  Update:    function (element,callback) {return this.takeAction("Update",element,callback)},
 
1408
  Reprocess: function (element,callback) {return this.takeAction("Reprocess",element,callback)},
 
1409
  Rerender:  function (element,callback) {return this.takeAction("Rerender",element,callback)},
 
1410
  
 
1411
  takeAction: function (action,element,callback) {
 
1412
    var ec = this.elementCallback(element,callback);
 
1413
    var queue = MathJax.Callback.Queue(["Clear",this.signal]);
 
1414
    for (var i = 0, m = ec.elements.length; i < m; i++) {
 
1415
      if (ec.elements[i]) {
 
1416
        var state = {
 
1417
          scripts: [],                  // filled in by prepareScripts
 
1418
          start: new Date().getTime(),  // timer for processing messages
 
1419
          i: 0, j: 0,                   // current script, current jax
 
1420
          jax: {},                      // scripts grouped by output jax
 
1421
          jaxIDs: []                    // id's of jax used
 
1422
        };
 
1423
        queue.Push(
 
1424
          ["Post",this.signal,["Begin "+action,ec.elements[i]]],
 
1425
          ["Post",this.signal,["Begin Math",ec.elements[i],action]],
 
1426
          ["prepareScripts",this,action,ec.elements[i],state],
 
1427
          ["Post",this.signal,["Begin Math Input",ec.elements[i],action]],
 
1428
          ["processInput",this,state],
 
1429
          ["Post",this.signal,["End Math Input",ec.elements[i],action]],
 
1430
          ["prepareOutput",this,state,"preProcess"],
 
1431
          ["Post",this.signal,["Begin Math Output",ec.elements[i],action]],
 
1432
          ["processOutput",this,state],
 
1433
          ["Post",this.signal,["End Math Output",ec.elements[i],action]],
 
1434
          ["prepareOutput",this,state,"postProcess"],
 
1435
          ["Post",this.signal,["End Math",ec.elements[i],action]],
 
1436
          ["Post",this.signal,["End "+action,ec.elements[i]]]
 
1437
        );
 
1438
      }
 
1439
    }
 
1440
    return queue.Push(ec.callback);
 
1441
  },
 
1442
  
 
1443
  scriptAction: {
 
1444
    Process: function (script) {},
 
1445
    Update: function (script) {
 
1446
      var jax = script.MathJax.elementJax;
 
1447
      if (jax && jax.needsUpdate()) {jax.Remove(true); script.MathJax.state = jax.STATE.UPDATE}
 
1448
        else {script.MathJax.state = jax.STATE.PROCESSED}
 
1449
    },
 
1450
    Reprocess: function (script) {
 
1451
      var jax = script.MathJax.elementJax;
 
1452
      if (jax) {jax.Remove(true); script.MathJax.state = jax.STATE.UPDATE}
 
1453
    },
 
1454
    Rerender: function (script) {
 
1455
      var jax = script.MathJax.elementJax;
 
1456
      if (jax) {jax.Remove(true); script.MathJax.state = jax.STATE.OUTPUT}
 
1457
    }
 
1458
  },
 
1459
  
 
1460
  prepareScripts: function (action,element,state) {
 
1461
    if (arguments.callee.disabled) return;
 
1462
    var scripts = this.elementScripts(element);
 
1463
    var STATE = MathJax.ElementJax.STATE;
 
1464
    for (var i = 0, m = scripts.length; i < m; i++) {
 
1465
      var script = scripts[i];
 
1466
      if (script.type && this.inputJax[script.type.replace(/ *;(.|\n)*/,"")]) {
 
1467
        if (script.MathJax) {
 
1468
          if (script.MathJax.elementJax && script.MathJax.elementJax.hover) {
 
1469
            MathJax.Extension.MathEvents.Hover.ClearHover(script.MathJax.elementJax);
 
1470
          }
 
1471
          if (script.MathJax.state !== STATE.PENDING) {this.scriptAction[action](script)}
 
1472
        }
 
1473
        if (!script.MathJax) {script.MathJax = {state: STATE.PENDING}}
 
1474
        if (script.MathJax.state !== STATE.PROCESSED) {state.scripts.push(script)}
 
1475
      }
 
1476
    }
 
1477
  },
 
1478
  
 
1479
  checkScriptSiblings: function (script) {
 
1480
    if (script.MathJax.checked) return;
 
1481
    var config = this.config, pre = script.previousSibling;
 
1482
    if (pre && pre.nodeName === "#text") {
 
1483
      var preJax,postJax, post = script.nextSibling;
 
1484
      if (post && post.nodeName !== "#text") {post = null}
 
1485
      if (config.preJax) {
 
1486
        if (typeof(config.preJax) === "string") {config.preJax = new RegExp(config.preJax+"$")}
 
1487
        preJax = pre.nodeValue.match(config.preJax);
 
1488
      }
 
1489
      if (config.postJax && post) {
 
1490
        if (typeof(config.postJax) === "string") {config.postJax = new RegExp("^"+config.postJax)}
 
1491
        postJax = post.nodeValue.match(config.postJax);
 
1492
      }
 
1493
      if (preJax && (!config.postJax || postJax)) {
 
1494
        pre.nodeValue  = pre.nodeValue.replace
 
1495
          (config.preJax,(preJax.length > 1? preJax[1] : ""));
 
1496
        pre = null;
 
1497
      }
 
1498
      if (postJax && (!config.preJax || preJax)) {
 
1499
        post.nodeValue = post.nodeValue.replace
 
1500
          (config.postJax,(postJax.length > 1? postJax[1] : ""));
 
1501
      }
 
1502
      if (pre && !pre.nodeValue.match(/\S/)) {pre = pre.previousSibling}
 
1503
    }
 
1504
    if (config.preRemoveClass && pre && pre.className === config.preRemoveClass)
 
1505
      {script.MathJax.preview = pre}
 
1506
    script.MathJax.checked = 1;
 
1507
  },
 
1508
  
 
1509
  processInput: function (state) {
 
1510
    var jax, STATE = MathJax.ElementJax.STATE;
 
1511
    var script, prev, m = state.scripts.length;
 
1512
    try {
 
1513
      //
 
1514
      //  Loop through the scripts
 
1515
      //
 
1516
      while (state.i < m) {
 
1517
        script = state.scripts[state.i]; if (!script) {state.i++; continue}
 
1518
        //
 
1519
        //  Remove previous error marker, if any
 
1520
        //
 
1521
        prev = script.previousSibling;
 
1522
        if (prev && prev.className === "MathJax_Error") {prev.parentNode.removeChild(prev)}
 
1523
        //
 
1524
        //  Check if already processed or needs processing
 
1525
        //
 
1526
        if (!script.MathJax || script.MathJax.state === STATE.PROCESSED) {state.i++; continue};
 
1527
        if (!script.MathJax.elementJax || script.MathJax.state === STATE.UPDATE) {
 
1528
          this.checkScriptSiblings(script);                 // remove preJax/postJax etc.
 
1529
          var type = script.type.replace(/ *;(.|\s)*/,"");  // the input jax type
 
1530
          jax = this.inputJax[type].Process(script,state);  // run the input jax
 
1531
          if (typeof jax === 'function') {                  // if a callback was returned
 
1532
            if (jax.called) continue;                       //   go back and call Process() again
 
1533
            this.RestartAfter(jax);                         //   wait for the callback
 
1534
          }
 
1535
          jax.Attach(script,this.inputJax[type].id);        // register the jax on the script
 
1536
          this.saveScript(jax,state,script,STATE);          // add script to state
 
1537
        } else if (script.MathJax.state === STATE.OUTPUT) {
 
1538
          this.saveScript(script.MathJax.elementJax,state,script,STATE); // add script to state
 
1539
        }
 
1540
        //
 
1541
        //  Go on to the next script, and check if we need to update the processing message
 
1542
        //
 
1543
        state.i++; var now = new Date().getTime();
 
1544
        if (now - state.start > this.processUpdateTime && state.i < state.scripts.length)
 
1545
          {state.start = now; this.RestartAfter(MathJax.Callback.Delay(1))}
 
1546
      }
 
1547
    } catch (err) {return this.processError(err,state,"Input")}
 
1548
    //
 
1549
    //  Put up final message, reset the state and return
 
1550
    //
 
1551
    if (state.scripts.length && this.config.showProcessingMessages)
 
1552
      {MathJax.Message.Set("Processing math: 100%",0)}
 
1553
    state.start = new Date().getTime(); state.i = state.j = 0;
 
1554
    return null;
 
1555
  },
 
1556
  saveScript: function (jax,state,script,STATE) {
 
1557
    //
 
1558
    //  Check that output jax exists
 
1559
    //
 
1560
    if (!this.outputJax[jax.mimeType]) {
 
1561
      script.MathJax.state = STATE.UPDATE;
 
1562
      throw Error("No output jax registered for "+jax.mimeType);
 
1563
    }
 
1564
    //
 
1565
    //  Record the output jax
 
1566
    //  and put this script in the queue for that jax
 
1567
    //
 
1568
    jax.outputJax = this.outputJax[jax.mimeType][0].id;
 
1569
    if (!state.jax[jax.outputJax]) {
 
1570
      if (state.jaxIDs.length === 0) {
 
1571
        // use original array until we know there are more (rather than two copies)
 
1572
        state.jax[jax.outputJax] = state.scripts;
 
1573
      } else {
 
1574
        if (state.jaxIDs.length === 1) // get the script so far for the existing jax
 
1575
          {state.jax[state.jaxIDs[0]] = state.scripts.slice(0,state.i)}
 
1576
        state.jax[jax.outputJax] = []; // start a new array for the new jax
 
1577
      }
 
1578
      state.jaxIDs.push(jax.outputJax); // save the ID of the jax
 
1579
    }
 
1580
    if (state.jaxIDs.length > 1) {state.jax[jax.outputJax].push(script)}
 
1581
    //
 
1582
    //  Mark script as needing output
 
1583
    //
 
1584
    script.MathJax.state = STATE.OUTPUT;
 
1585
  },
 
1586
  
 
1587
  //
 
1588
  //  Pre- and post-process scripts by jax
 
1589
  //    (to get scaling factors, hide/show output, and so on)
 
1590
  //  Since this can cause the jax to load, we need to trap restarts
 
1591
  //
 
1592
  prepareOutput: function (state,method) {
 
1593
    while (state.j < state.jaxIDs.length) {
 
1594
      var id = state.jaxIDs[state.j], JAX = MathJax.OutputJax[id];
 
1595
      if (JAX[method]) {
 
1596
        try {
 
1597
          var result = JAX[method](state);
 
1598
          if (typeof result === 'function') {
 
1599
            if (result.called) continue;  // go back and try again
 
1600
            this.RestartAfter(result);
 
1601
          }
 
1602
        } catch (err) {
 
1603
          if (!err.restart) {
 
1604
            MathJax.Message.Set("Error preparing "+id+" output ("+method+")",null,600);
 
1605
            MathJax.Hub.lastPrepError = err;
 
1606
            state.j++;
 
1607
          }
 
1608
          return MathJax.Callback.After(["prepareOutput",this,state,method],err.restart);
 
1609
        }
 
1610
      }
 
1611
      state.j++;
 
1612
    }
 
1613
    return null;
 
1614
  },
 
1615
 
 
1616
  processOutput: function (state) {
 
1617
    var result, STATE = MathJax.ElementJax.STATE, script, m = state.scripts.length;
 
1618
    try {
 
1619
      //
 
1620
      //  Loop through the scripts
 
1621
      //
 
1622
      while (state.i < m) {
 
1623
        //
 
1624
        //  Check that there is an element jax
 
1625
        //
 
1626
        script = state.scripts[state.i]; if (!script || !script.MathJax) {state.i++; continue}
 
1627
        var jax = script.MathJax.elementJax; if (!jax) {state.i++; continue}
 
1628
        //
 
1629
        //  Call the output Jax's Process method (which will be its Translate()
 
1630
        //  method once loaded).  Mark it as complete and remove the preview.
 
1631
        //
 
1632
        result = MathJax.OutputJax[jax.outputJax].Process(script,state);
 
1633
        script.MathJax.state = STATE.PROCESSED; state.i++;
 
1634
        if (script.MathJax.preview) {script.MathJax.preview.innerHTML = ""}
 
1635
        //
 
1636
        //  Signal that new math is available
 
1637
        //
 
1638
        this.signal.Post(["New Math",jax.inputID]); // FIXME: wait for this?  (i.e., restart if returns uncalled callback)
 
1639
        //
 
1640
        //  Update the processing message, if needed
 
1641
        //
 
1642
        var now = new Date().getTime();
 
1643
        if (now - state.start > this.processUpdateTime && state.i < state.scripts.length)
 
1644
          {state.start = now; this.RestartAfter(MathJax.Callback.Delay(this.processUpdateDelay))}
 
1645
      }
 
1646
    } catch (err) {return this.processError(err,state,"Output")}
 
1647
    //
 
1648
    //  Put up the typesetting-complete message
 
1649
    //
 
1650
    if (state.scripts.length && this.config.showProcessingMessages) {
 
1651
      MathJax.Message.Set("Typesetting math: 100%",0);
 
1652
      MathJax.Message.Clear(0);
 
1653
    }
 
1654
    state.i = state.j = 0;
 
1655
    return null;
 
1656
  },
 
1657
  
 
1658
  processMessage: function (state,type) {
 
1659
    var m = Math.floor(state.i/(state.scripts.length)*100);
 
1660
    var message = (type === "Output" ? "Typesetting" : "Processing");
 
1661
    if (this.config.showProcessingMessages) {MathJax.Message.Set(message+" math: "+m+"%",0)}
 
1662
  },
 
1663
 
 
1664
  processError: function (err,state,type) {
 
1665
    if (!err.restart) {
 
1666
      if (!this.config.errorSettings.message) {throw err}
 
1667
      this.formatError(state.scripts[state.i],err); state.i++;
 
1668
    }
 
1669
    this.processMessage(state,type);
 
1670
    return MathJax.Callback.After(["process"+type,this,state],err.restart);
 
1671
  },
 
1672
  
 
1673
  formatError: function (script,err) {
 
1674
    var error = MathJax.HTML.Element("span",{className:"MathJax_Error"},this.config.errorSettings.message);
 
1675
    error.jaxID = "Error";
 
1676
    if (MathJax.Extension.MathEvents) {
 
1677
      error.oncontextmenu = MathJax.Extension.MathEvents.Event.Menu;
 
1678
      error.onmousedown = MathJax.Extension.MathEvents.Event.Mousedown;
 
1679
    } else {
 
1680
      MathJax.Ajax.Require("[MathJax]/extensions/MathEvents.js",function () {
 
1681
        error.oncontextmenu = MathJax.Extension.MathEvents.Event.Menu;
 
1682
        error.onmousedown = MathJax.Extension.MathEvents.Event.Mousedown;
 
1683
      });
 
1684
    }
 
1685
    script.parentNode.insertBefore(error,script);
 
1686
    if (script.MathJax.preview) {script.MathJax.preview.innerHTML = ""}
 
1687
    this.lastError = err;
 
1688
    this.signal.Post(["Math Processing Error",script,err]);
 
1689
  },
 
1690
  
 
1691
  RestartAfter: function (callback) {
 
1692
    throw this.Insert(Error("restart"),{restart: MathJax.Callback(callback)});
 
1693
  },
 
1694
  
 
1695
  elementCallback: function (element,callback) {
 
1696
    if (callback == null && (element instanceof Array || typeof element === 'function'))
 
1697
      {try {MathJax.Callback(element); callback = element; element = null} catch(e) {}}
 
1698
    if (element == null) {element = this.config.elements || []}
 
1699
    if (!(element instanceof Array)) {element = [element]}
 
1700
    element = [].concat(element); // make a copy so the original isn't changed
 
1701
    for (var i = 0, m = element.length; i < m; i++)
 
1702
      {if (typeof(element[i]) === 'string') {element[i] = document.getElementById(element[i])}}
 
1703
    if (element.length == 0) {element.push(document.body)}
 
1704
    if (!callback) {callback = {}}
 
1705
    return {elements: element, callback: callback};
 
1706
  },
 
1707
  
 
1708
  elementScripts: function (element) {
 
1709
    if (typeof(element) === 'string') {element = document.getElementById(element)}
 
1710
    if (element == null) {element = document.body}
 
1711
    if (element.tagName != null && element.tagName.toLowerCase() === "script") {return [element]}
 
1712
    return element.getElementsByTagName("script");
 
1713
  },
 
1714
  
 
1715
  Insert: function (dst,src) {
 
1716
    for (var id in src) {if (src.hasOwnProperty(id)) {
 
1717
      // allow for concatenation of arrays?
 
1718
      if (typeof src[id] === 'object' && !(src[id] instanceof Array) &&
 
1719
         (typeof dst[id] === 'object' || typeof dst[id] === 'function')) {
 
1720
        this.Insert(dst[id],src[id]);
 
1721
      } else {
 
1722
        dst[id] = src[id];
 
1723
      }
 
1724
    }}
 
1725
    return dst;
 
1726
  }
 
1727
};
 
1728
MathJax.Hub.Insert(MathJax.Hub.config.styles,MathJax.Message.styles);
 
1729
MathJax.Hub.Insert(MathJax.Hub.config.styles,{".MathJax_Error":MathJax.Hub.config.errorSettings.style});
 
1730
 
 
1731
//
 
1732
//  Storage area for extensions and preprocessors
 
1733
//
 
1734
MathJax.Extension = {};
 
1735
 
 
1736
//
 
1737
//  Hub Startup code
 
1738
//
 
1739
MathJax.Hub.Configured = MathJax.Callback({}); // called when configuration is complete
 
1740
MathJax.Hub.Startup = {
 
1741
  script: "", // the startup script from the SCRIPT call that loads MathJax.js
 
1742
  queue:   MathJax.Callback.Queue(),           // Queue used for startup actions
 
1743
  signal:  MathJax.Callback.Signal("Startup"), // Signal used for startup events
 
1744
  params:  {},
 
1745
 
 
1746
  //
 
1747
  //  Load the configuration files
 
1748
  //
 
1749
  Config: function () {
 
1750
    this.queue.Push(["Post",this.signal,"Begin Config"]);
 
1751
    //
 
1752
    //  Check for user cookie configuration
 
1753
    //
 
1754
    var user = MathJax.HTML.Cookie.Get("user");
 
1755
    if (user.URL || user.Config) {
 
1756
      if (confirm(
 
1757
         "MathJax has found a user-configuration cookie that includes code to be run.  " +
 
1758
         "Do you want to run it?\n\n"+
 
1759
         "(You should press Cancel unless you set up the cookie yourself.)"
 
1760
      )) {
 
1761
        if (user.URL) {this.queue.Push(["Require",MathJax.Ajax,user.URL])}
 
1762
        if (user.Config) {this.queue.Push(new Function(user.Config))}
 
1763
      } else {MathJax.HTML.Cookie.Set("user",{})}
 
1764
    }
 
1765
    //
 
1766
    //  Run the config files, if any are given in the parameter list
 
1767
    //
 
1768
    if (this.params.config) {
 
1769
      var files = this.params.config.split(/,/);
 
1770
      for (var i = 0, m = files.length; i < m; i++) {
 
1771
        if (!files[i].match(/\.js$/)) {files[i] += ".js"}
 
1772
        this.queue.Push(["Require",MathJax.Ajax,this.URL("config",files[i])]);
 
1773
      }
 
1774
    }
 
1775
    //
 
1776
    //  Run the deprecated configuration script, if any (ignoring return value)
 
1777
    //  Wait for the startup delay signal
 
1778
    //  Run the mathjax-config blocks
 
1779
    //  Handle the default configuration (v1.0 compatible)
 
1780
    //  Load the files in the configuration's config array
 
1781
    //
 
1782
    if (this.script.match(/\S/)) {this.queue.Push(this.script+";\n1;")}
 
1783
    this.queue.Push(
 
1784
      ["ConfigDelay",this],
 
1785
      ["ConfigBlocks",this],
 
1786
      ["ConfigDefault",this],
 
1787
      [function (THIS) {return THIS.loadArray(MathJax.Hub.config.config,"config",null,true)},this],
 
1788
      ["Post",this.signal,"End Config"]
 
1789
    );
 
1790
  },
 
1791
  //
 
1792
  //  Return the delay callback
 
1793
  //
 
1794
  ConfigDelay: function () {
 
1795
    var delay = this.params.delayStartupUntil || MathJax.Hub.config.delayStartupUntil;
 
1796
    if (delay === "onload") {return this.onload}
 
1797
    if (delay === "configured") {return MathJax.Hub.Configured}
 
1798
    return delay;
 
1799
  },
 
1800
  //
 
1801
  //  Run the scipts of type=text/x-mathajx-config
 
1802
  //
 
1803
  ConfigBlocks: function () {
 
1804
    var scripts = document.getElementsByTagName("script");
 
1805
    var last = null, queue = MathJax.Callback.Queue();
 
1806
    for (var i = 0, m = scripts.length; i < m; i++) {
 
1807
      var type = String(scripts[i].type).replace(/ /g,"");
 
1808
      if (type.match(/^text\/x-mathjax-config(;.*)?$/) && !type.match(/;executed=true/)) {
 
1809
        scripts[i].type += ";executed=true";
 
1810
        last = queue.Push(scripts[i].innerHTML+";\n1;");
 
1811
      }
 
1812
    }
 
1813
    return last;
 
1814
  },
 
1815
  //
 
1816
  //  Check for v1.0 no-configuration and put up a warning message.
 
1817
  //
 
1818
  ConfigDefault: function () {
 
1819
    var CONFIG = MathJax.Hub.config;
 
1820
    if (CONFIG["v1.0-compatible"] && (CONFIG.jax||[]).length === 0 &&
 
1821
        !this.params.config && (CONFIG.config||[]).length === 0)
 
1822
      {return MathJax.Ajax.Require(this.URL("extensions","v1.0-warning.js"))}
 
1823
  },
 
1824
 
 
1825
  //
 
1826
  //  Read cookie and set up menu defaults
 
1827
  //  (adjust the jax to accommodate renderer preferences)
 
1828
  //
 
1829
  Cookie: function () {
 
1830
    return this.queue.Push(
 
1831
      ["Post",this.signal,"Begin Cookie"],
 
1832
      ["Get",MathJax.HTML.Cookie,"menu",MathJax.Hub.config.menuSettings],
 
1833
      [function (config) {
 
1834
        var renderer = config.menuSettings.renderer, jax = config.jax;
 
1835
        if (renderer) {
 
1836
          var name = "output/"+renderer; jax.sort();
 
1837
          for (var i = 0, m = jax.length; i < m; i++) {
 
1838
            if (jax[i].substr(0,7) === "output/") break;
 
1839
          }
 
1840
          if (i == m-1) {jax.pop()} else {
 
1841
            while (i < m) {if (jax[i] === name) {jax.splice(i,1); break}; i++}
 
1842
          }
 
1843
          jax.unshift(name);
 
1844
        }
 
1845
      },MathJax.Hub.config],
 
1846
      ["Post",this.signal,"End Cookie"]
 
1847
    );
 
1848
  },
 
1849
  //
 
1850
  //  Setup stylesheets and extra styles
 
1851
  //
 
1852
  Styles: function () {
 
1853
    return this.queue.Push(
 
1854
      ["Post",this.signal,"Begin Styles"],
 
1855
      ["loadArray",this,MathJax.Hub.config.styleSheets,"config"],
 
1856
      ["Styles",MathJax.Ajax,MathJax.Hub.config.styles],
 
1857
      ["Post",this.signal,"End Styles"]
 
1858
    );
 
1859
  },
 
1860
  //
 
1861
  //  Load the input and output jax
 
1862
  //
 
1863
  Jax: function () {
 
1864
    var config = MathJax.Hub.config, jax = MathJax.Hub.outputJax;
 
1865
    //  Save the order of the output jax since they are loading asynchronously
 
1866
    for (var i = 0, m = config.jax.length, k = 0; i < m; i++) {
 
1867
      var name = config.jax[i].substr(7);
 
1868
      if (config.jax[i].substr(0,7) === "output/" && jax.order[name] == null)
 
1869
        {jax.order[name] = k; k++}
 
1870
    }
 
1871
    var queue = MathJax.Callback.Queue();
 
1872
    return queue.Push(
 
1873
      ["Post",this.signal,"Begin Jax"],
 
1874
      ["loadArray",this,config.jax,"jax","config.js"],
 
1875
      ["Post",this.signal,"End Jax"]
 
1876
    );
 
1877
  },
 
1878
  //
 
1879
  //  Load the extensions
 
1880
  //
 
1881
  Extensions: function () {
 
1882
    var queue = MathJax.Callback.Queue();
 
1883
    return queue.Push(
 
1884
      ["Post",this.signal,"Begin Extensions"],
 
1885
      ["loadArray",this,MathJax.Hub.config.extensions,"extensions"],
 
1886
      ["Post",this.signal,"End Extensions"]
 
1887
    );
 
1888
  },
 
1889
  
 
1890
  //
 
1891
  //  Initialize the Message system
 
1892
  //
 
1893
  Message: function () {
 
1894
    MathJax.Message.Init(true);
 
1895
  },
 
1896
  
 
1897
  //
 
1898
  //  Set the math menu renderer, if it isn't already
 
1899
  //  (this must come after the jax are loaded)
 
1900
  //
 
1901
  Menu: function () {
 
1902
    var menu = MathJax.Hub.config.menuSettings, jax = MathJax.Hub.outputJax, registered;
 
1903
    for (var id in jax) {if (jax.hasOwnProperty(id)) {
 
1904
      if (jax[id].length) {registered = jax[id]; break}
 
1905
    }}
 
1906
    if (registered && registered.length) {
 
1907
      if (menu.renderer && menu.renderer !== registered[0].id)
 
1908
        {registered.unshift(MathJax.OutputJax[menu.renderer])}
 
1909
      menu.renderer = registered[0].id;
 
1910
    }
 
1911
  },
 
1912
  
 
1913
  //
 
1914
  //  Set the location to the designated hash position
 
1915
  //
 
1916
  Hash: function () {
 
1917
    if (MathJax.Hub.config.positionToHash && document.location.hash &&
 
1918
        document.body && document.body.scrollIntoView) {
 
1919
      var name = document.location.hash.substr(1);
 
1920
      var target = document.getElementById(name);
 
1921
      if (!target) {
 
1922
        var a = document.getElementsByTagName("a");
 
1923
        for (var i = 0, m = a.length; i < m; i++)
 
1924
          {if (a[i].name === name) {target = a[i]; break}}
 
1925
      }
 
1926
      if (target) {
 
1927
        while (!target.scrollIntoView) {target = target.parentNode}
 
1928
        target = this.HashCheck(target);
 
1929
        if (target && target.scrollIntoView)
 
1930
          {setTimeout(function () {target.scrollIntoView(true)},1)}
 
1931
      }
 
1932
    }
 
1933
  },
 
1934
  HashCheck: function (target) {
 
1935
    if (target.isMathJax) {
 
1936
      var jax = MathJax.Hub.getJaxFor(target);
 
1937
      if (jax && MathJax.OutputJax[jax.outputJax].hashCheck)
 
1938
        {target = MathJax.OutputJax[jax.outputJax].hashCheck(target)}
 
1939
    }
 
1940
    return target;
 
1941
  },
 
1942
  
 
1943
  //
 
1944
  //  Load the Menu and Zoom code, if it hasn't already been loaded.
 
1945
  //  This is called after the initial typeset, so should no longer be
 
1946
  //  competing with other page loads, but will make these available
 
1947
  //  if needed later on.
 
1948
  //
 
1949
  MenuZoom: function () {
 
1950
    if (!MathJax.Extension.MathMenu) {
 
1951
      setTimeout(
 
1952
        MathJax.Callback(["Require",MathJax.Ajax,"[MathJax]/extensions/MathMenu.js",{}]),
 
1953
        1000
 
1954
      );
 
1955
    }
 
1956
    if (!MathJax.Extension.MathZoom) {
 
1957
      setTimeout(
 
1958
        MathJax.Callback(["Require",MathJax.Ajax,"[MathJax]/extensions/MathZoom.js",{}]),
 
1959
        2000
 
1960
      );
 
1961
    }
 
1962
  },
 
1963
  
 
1964
  //
 
1965
  //  Setup the onload callback
 
1966
  //
 
1967
  onLoad: function () {
 
1968
    var onload = this.onload =
 
1969
      MathJax.Callback(function () {MathJax.Hub.Startup.signal.Post("onLoad")});
 
1970
    if (document.body && document.readyState)
 
1971
      if (MathJax.Hub.Browser.isMSIE) {
 
1972
        // IE can change from loading to interactive before
 
1973
        //  full page is ready, so go with complete (even though
 
1974
        //  that means we may have to wait longer).
 
1975
        if (document.readyState === "complete") {return [onload]}
 
1976
      } else if (document.readyState !== "loading") {return [onload]}
 
1977
    if (window.addEventListener) {
 
1978
      window.addEventListener("load",onload,false);
 
1979
      if (!this.params.noDOMContentEvent)
 
1980
        {window.addEventListener("DOMContentLoaded",onload,false)}
 
1981
    }
 
1982
    else if (window.attachEvent) {window.attachEvent("onload",onload)}
 
1983
    else {window.onload = onload}
 
1984
    return onload;
 
1985
  },
 
1986
 
 
1987
  //
 
1988
  //  Perform the initial typesetting (or skip if configuration says to)
 
1989
  //
 
1990
  Typeset: function (element,callback) {
 
1991
    if (MathJax.Hub.config.skipStartupTypeset) {return function () {}}
 
1992
    return this.queue.Push(
 
1993
      ["Post",this.signal,"Begin Typeset"],
 
1994
      ["Typeset",MathJax.Hub,element,callback],
 
1995
      ["Post",this.signal,"End Typeset"]
 
1996
    );
 
1997
  },
 
1998
 
 
1999
  //
 
2000
  //  Create a URL in the MathJax hierarchy
 
2001
  //
 
2002
  URL: function (dir,name) {
 
2003
    if (!name.match(/^([a-z]+:\/\/|\[|\/)/)) {name = "[MathJax]/"+dir+"/"+name}
 
2004
    return name;
 
2005
  },
 
2006
 
 
2007
  //
 
2008
  //  Load an array of files, waiting for all of them
 
2009
  //  to be loaded before going on
 
2010
  //
 
2011
  loadArray: function (files,dir,name,synchronous) {
 
2012
    if (files) {
 
2013
      if (!(files instanceof Array)) {files = [files]}
 
2014
      if (files.length) {
 
2015
        var queue = MathJax.Callback.Queue(), callback = {}, file;
 
2016
        for (var i = 0, m = files.length; i < m; i++) {
 
2017
          file = this.URL(dir,files[i]);
 
2018
          if (name) {file += "/" + name}
 
2019
          if (synchronous) {queue.Push(["Require",MathJax.Ajax,file,callback])}
 
2020
                      else {queue.Push(MathJax.Ajax.Require(file,callback))}
 
2021
        }
 
2022
        return queue.Push({}); // wait for everything to finish
 
2023
      }
 
2024
    }
 
2025
    return null;
 
2026
  }
 
2027
  
 
2028
};
 
2029
 
 
2030
 
 
2031
/**********************************************************/
 
2032
 
 
2033
(function (BASENAME) {
 
2034
  var BASE = window[BASENAME], ROOT = "["+BASENAME+"]";
 
2035
  var HUB = BASE.Hub, AJAX = BASE.Ajax, CALLBACK = BASE.Callback;
 
2036
 
 
2037
  var JAX = MathJax.Object.Subclass({
 
2038
    JAXFILE: "jax.js",
 
2039
    require: null, // array of files to load before jax.js is complete
 
2040
    config: {},
 
2041
    //
 
2042
    //  Make a subclass and return an instance of it.
 
2043
    //  (FIXME: should we replace config with a copy of the constructor's
 
2044
    //   config?  Otherwise all subclasses share the same config structure.)
 
2045
    //
 
2046
    Init: function (def,cdef) {
 
2047
      if (arguments.length === 0) {return this}
 
2048
      return (this.constructor.Subclass(def,cdef))();
 
2049
    },
 
2050
    //
 
2051
    //  Augment by merging with class definition (not replacing)
 
2052
    //
 
2053
    Augment: function (def,cdef) {
 
2054
      var cObject = this.constructor, ndef = {};
 
2055
      if (def != null) {
 
2056
        for (var id in def) {if (def.hasOwnProperty(id)) {
 
2057
          if (typeof def[id] === "function")
 
2058
            {cObject.protoFunction(id,def[id])} else {ndef[id] = def[id]}
 
2059
        }}
 
2060
        // MSIE doesn't list toString even if it is not native so handle it separately
 
2061
        if (def.toString !== cObject.prototype.toString && def.toString !== {}.toString)
 
2062
          {cObject.protoFunction('toString',def.toString)}
 
2063
      }
 
2064
      HUB.Insert(cObject.prototype,ndef);
 
2065
      cObject.Augment(null,cdef);
 
2066
      return this;
 
2067
    },
 
2068
    Translate: function (script,state) {
 
2069
      throw Error(this.directory+"/"+this.JAXFILE+" failed to define the Translate() method");
 
2070
    },
 
2071
    Register: function (mimetype) {},
 
2072
    Config: function () {
 
2073
      this.config = HUB.CombineConfig(this.id,this.config);
 
2074
      if (this.config.Augment) {this.Augment(this.config.Augment)}
 
2075
    },
 
2076
    Startup: function () {},
 
2077
    loadComplete: function (file) {
 
2078
      if (file === "config.js") {
 
2079
        return AJAX.loadComplete(this.directory+"/"+file);
 
2080
      } else {
 
2081
        var queue = CALLBACK.Queue();
 
2082
        queue.Push(
 
2083
          HUB.Register.StartupHook("End Config",{}), // wait until config complete
 
2084
          ["Post",HUB.Startup.signal,this.id+" Jax Config"],
 
2085
          ["Config",this],
 
2086
          ["Post",HUB.Startup.signal,this.id+" Jax Require"],
 
2087
          // Config may set the required and extensions array,
 
2088
          //  so use functions to delay making the reference until needed
 
2089
          [function (THIS) {return MathJax.Hub.Startup.loadArray(THIS.require,this.directory)},this],
 
2090
          [function (config,id) {return MathJax.Hub.Startup.loadArray(config.extensions,"extensions/"+id)},this.config||{},this.id],
 
2091
          ["Post",HUB.Startup.signal,this.id+" Jax Startup"],
 
2092
          ["Startup",this],
 
2093
          ["Post",HUB.Startup.signal,this.id+" Jax Ready"]
 
2094
        );
 
2095
        if (this.copyTranslate) {
 
2096
          queue.Push(
 
2097
            [function (THIS) {
 
2098
              THIS.preProcess  = THIS.preTranslate;
 
2099
              THIS.Process     = THIS.Translate;
 
2100
              THIS.postProcess = THIS.postTranslate;
 
2101
            },this.constructor.prototype]
 
2102
          );
 
2103
        }
 
2104
        return queue.Push(["loadComplete",AJAX,this.directory+"/"+file]);
 
2105
      }
 
2106
    }
 
2107
  },{
 
2108
    id: "Jax",
 
2109
    version: "2.1",
 
2110
    directory: ROOT+"/jax",
 
2111
    extensionDir: ROOT+"/extensions"
 
2112
  });
 
2113
 
 
2114
  /***********************************/
 
2115
 
 
2116
  BASE.InputJax = JAX.Subclass({
 
2117
    elementJax: "mml",  // the element jax to load for this input jax
 
2118
    copyTranslate: true,
 
2119
    Process: function (script,state) {
 
2120
      var queue = CALLBACK.Queue(), file;
 
2121
      // Load any needed element jax
 
2122
      var jax = this.elementJax; if (!(jax instanceof Array)) {jax = [jax]}
 
2123
      for (var i = 0, m = jax.length; i < m; i++) {
 
2124
        file = BASE.ElementJax.directory+"/"+jax[i]+"/"+this.JAXFILE;
 
2125
        if (!this.require) {this.require = []}
 
2126
          else if (!(this.require instanceof Array)) {this.require = [this.require]};
 
2127
        this.require.push(file);  // so Startup will wait for it to be loaded
 
2128
        queue.Push(AJAX.Require(file));
 
2129
      }
 
2130
      // Load the input jax
 
2131
      file = this.directory+"/"+this.JAXFILE;
 
2132
      var load = queue.Push(AJAX.Require(file));
 
2133
      if (!load.called) {
 
2134
        this.constructor.prototype.Process = function () {
 
2135
          if (!load.called) {return load}
 
2136
          throw Error(file+" failed to load properly");
 
2137
        }
 
2138
      }
 
2139
      // Load the associated output jax
 
2140
      jax = HUB.outputJax["jax/"+jax[0]];
 
2141
      if (jax) {queue.Push(AJAX.Require(jax[0].directory+"/"+this.JAXFILE))}
 
2142
      return queue.Push({});
 
2143
    },
 
2144
    needsUpdate: function (jax) {
 
2145
      var script = jax.SourceElement();
 
2146
      return (jax.originalText !== BASE.HTML.getScript(script));
 
2147
    },
 
2148
    Register: function (mimetype) {
 
2149
      if (!HUB.inputJax) {HUB.inputJax = {}}
 
2150
      HUB.inputJax[mimetype] = this;
 
2151
    }
 
2152
  },{
 
2153
    id: "InputJax",
 
2154
    version: "2.1",
 
2155
    directory: JAX.directory+"/input",
 
2156
    extensionDir: JAX.extensionDir
 
2157
  });
 
2158
 
 
2159
  /***********************************/
 
2160
 
 
2161
  BASE.OutputJax = JAX.Subclass({
 
2162
    copyTranslate: true,
 
2163
    preProcess: function (state) {
 
2164
      var load, file = this.directory+"/"+this.JAXFILE;
 
2165
      this.constructor.prototype.preProcess = function (state) {
 
2166
        if (!load.called) {return load}
 
2167
        throw Error(file+" failed to load properly");
 
2168
      }
 
2169
      load = AJAX.Require(file);
 
2170
      return load;
 
2171
    },
 
2172
    Register: function (mimetype) {
 
2173
      var jax = HUB.outputJax;
 
2174
      if (!jax[mimetype]) {jax[mimetype] = []}
 
2175
      //  If the output jax is earlier in the original configuration list, put it first here
 
2176
      if (jax[mimetype].length && (this.id === HUB.config.menuSettings.renderer ||
 
2177
            (jax.order[this.id]||0) < (jax.order[jax[mimetype][0].id]||0)))
 
2178
        {jax[mimetype].unshift(this)} else {jax[mimetype].push(this)}
 
2179
      //  Make sure the element jax is loaded before Startup is called
 
2180
      if (!this.require) {this.require = []}
 
2181
        else if (!(this.require instanceof Array)) {this.require = [this.require]};
 
2182
      this.require.push(BASE.ElementJax.directory+"/"+(mimetype.split(/\//)[1])+"/"+this.JAXFILE);
 
2183
    },
 
2184
    Remove: function (jax) {}
 
2185
  },{
 
2186
    id: "OutputJax",
 
2187
    version: "2.1",
 
2188
    directory: JAX.directory+"/output",
 
2189
    extensionDir: JAX.extensionDir,
 
2190
    fontDir: ROOT+(BASE.isPacked?"":"/..")+"/fonts",
 
2191
    imageDir: ROOT+(BASE.isPacked?"":"/..")+"/images"
 
2192
  });
 
2193
  
 
2194
  /***********************************/
 
2195
 
 
2196
  BASE.ElementJax = JAX.Subclass({
 
2197
    // make a subclass, not an instance
 
2198
    Init: function (def,cdef) {return this.constructor.Subclass(def,cdef)},
 
2199
    
 
2200
    inputJax: null,
 
2201
    outputJax: null,
 
2202
    inputID: null,
 
2203
    originalText: "",
 
2204
    mimeType: "",
 
2205
    
 
2206
    Text: function (text,callback) {
 
2207
      var script = this.SourceElement();
 
2208
      BASE.HTML.setScript(script,text);
 
2209
      script.MathJax.state = this.STATE.UPDATE;
 
2210
      return HUB.Update(script,callback);
 
2211
    },
 
2212
    Reprocess: function (callback) {
 
2213
      var script = this.SourceElement();
 
2214
      script.MathJax.state = this.STATE.UPDATE;
 
2215
      return HUB.Reprocess(script,callback);
 
2216
    },
 
2217
    Update: function (callback) {return this.Rerender(callback)},
 
2218
    Rerender: function (callback) {
 
2219
      var script = this.SourceElement();
 
2220
      script.MathJax.state = this.STATE.OUTPUT;
 
2221
      return HUB.Process(script,callback);
 
2222
    },
 
2223
    Remove: function (keep) {
 
2224
      if (this.hover) {this.hover.clear(this)}
 
2225
      BASE.OutputJax[this.outputJax].Remove(this);
 
2226
      if (!keep) {
 
2227
        HUB.signal.Post(["Remove Math",this.inputID]); // wait for this to finish?
 
2228
        this.Detach();
 
2229
      }
 
2230
    },
 
2231
    needsUpdate: function () {
 
2232
      return BASE.InputJax[this.inputJax].needsUpdate(this);
 
2233
    },
 
2234
 
 
2235
    SourceElement: function () {return document.getElementById(this.inputID)},
 
2236
    
 
2237
    Attach: function (script,inputJax) {
 
2238
      var jax = script.MathJax.elementJax;
 
2239
      if (script.MathJax.state === this.STATE.UPDATE) {
 
2240
        jax.Clone(this);
 
2241
      } else {
 
2242
        jax = script.MathJax.elementJax = this;
 
2243
        if (script.id) {this.inputID = script.id}
 
2244
          else {script.id = this.inputID = BASE.ElementJax.GetID(); this.newID = 1}
 
2245
      }
 
2246
      jax.originalText = BASE.HTML.getScript(script);
 
2247
      jax.inputJax = inputJax;
 
2248
      if (jax.root) {jax.root.inputID = jax.inputID}
 
2249
      return jax;
 
2250
    },
 
2251
    Detach: function () {
 
2252
      var script = this.SourceElement(); if (!script) return;
 
2253
      try {delete script.MathJax} catch(err) {script.MathJax = null}
 
2254
      if (this.newID) {script.id = ""}
 
2255
    },
 
2256
    Clone: function (jax) {
 
2257
      var id;
 
2258
      for (id in this) {
 
2259
        if (!this.hasOwnProperty(id)) continue;
 
2260
        if (typeof(jax[id]) === 'undefined' && id !== 'newID') {delete this[id]}
 
2261
      }
 
2262
      for (id in jax) {
 
2263
        if (!jax.hasOwnProperty(id)) continue;
 
2264
        if (typeof(this[id]) === 'undefined' || (this[id] !== jax[id] && id !== 'inputID'))
 
2265
          {this[id] = jax[id]}
 
2266
      }
 
2267
    }
 
2268
  },{
 
2269
    id: "ElementJax",
 
2270
    version: "2.1",
 
2271
    directory: JAX.directory+"/element",
 
2272
    extensionDir: JAX.extensionDir,
 
2273
    ID: 0,  // jax counter (for IDs)
 
2274
    STATE: {
 
2275
      PENDING: 1,      // script is identified as math but not yet processed
 
2276
      PROCESSED: 2,    // script has been processed
 
2277
      UPDATE: 3,       // elementJax should be updated
 
2278
      OUTPUT: 4        // output should be updated (input is OK)
 
2279
    },
 
2280
    
 
2281
    GetID: function () {this.ID++; return "MathJax-Element-"+this.ID},
 
2282
    Subclass: function () {
 
2283
      var obj = JAX.Subclass.apply(this,arguments);
 
2284
      obj.loadComplete = this.prototype.loadComplete;
 
2285
      return obj;
 
2286
    }
 
2287
  });
 
2288
  BASE.ElementJax.prototype.STATE = BASE.ElementJax.STATE;
 
2289
 
 
2290
  //
 
2291
  //  Some "Fake" jax used to allow menu access for "Math Processing Error" messages
 
2292
  //
 
2293
  BASE.OutputJax.Error = {
 
2294
    id: "Error", version: "2.1", config: {},
 
2295
    ContextMenu: function () {return BASE.Extension.MathEvents.Event.ContextMenu.apply(BASE.Extension.MathEvents.Event,arguments)},
 
2296
    Mousedown:   function () {return BASE.Extension.MathEvents.Event.AltContextMenu.apply(BASE.Extension.MathEvents.Event,arguments)},
 
2297
    getJaxFromMath: function () {return {inputJax:"Error", outputJax:"Error", originalText:"Math Processing Error"}}
 
2298
  };
 
2299
  BASE.InputJax.Error = {
 
2300
    id: "Error", version: "2.1", config: {},
 
2301
    sourceMenuTitle: "Error Message"
 
2302
  };
 
2303
  
 
2304
})("MathJax");
 
2305
 
 
2306
/**********************************************************/
 
2307
 
 
2308
(function (BASENAME) {
 
2309
  var BASE = window[BASENAME];
 
2310
  if (!BASE) {BASE = window[BASENAME] = {}}
 
2311
 
 
2312
  var HUB = BASE.Hub; var STARTUP = HUB.Startup; var CONFIG = HUB.config;
 
2313
  var HEAD = document.getElementsByTagName("head")[0];
 
2314
  if (!HEAD) {HEAD = document.childNodes[0]};
 
2315
  var scripts = (document.documentElement || document).getElementsByTagName("script");
 
2316
  var namePattern = new RegExp("(^|/)"+BASENAME+"\\.js(\\?.*)?$");
 
2317
  for (var i = scripts.length-1; i >= 0; i--) {
 
2318
    if ((scripts[i].src||"").match(namePattern)) {
 
2319
      STARTUP.script = scripts[i].innerHTML;
 
2320
      if (RegExp.$2) {
 
2321
        var params = RegExp.$2.substr(1).split(/\&/);
 
2322
        for (var j = 0, m = params.length; j < m; j++) {
 
2323
          var KV = params[j].match(/(.*)=(.*)/);
 
2324
          if (KV) {STARTUP.params[unescape(KV[1])] = unescape(KV[2])}
 
2325
        }
 
2326
      }
 
2327
      CONFIG.root = scripts[i].src.replace(/(^|\/)[^\/]*(\?.*)?$/,'');
 
2328
      break;
 
2329
    }
 
2330
  }
 
2331
  BASE.Ajax.config = CONFIG;
 
2332
 
 
2333
  var BROWSERS = {
 
2334
    isMac:       (navigator.platform.substr(0,3) === "Mac"),
 
2335
    isPC:        (navigator.platform.substr(0,3) === "Win"),
 
2336
    isMSIE:      (window.ActiveXObject != null && window.clipboardData != null),
 
2337
    isFirefox:   ((window.netscape != null || window.mozPaintCount != null) &&
 
2338
                     document.ATTRIBUTE_NODE != null && !window.opera),
 
2339
    isSafari:    (navigator.userAgent.match(/ (Apple)?WebKit\//) != null &&
 
2340
                     (!window.chrome || window.chrome.loadTimes == null)),
 
2341
    isChrome:    (window.chrome != null && window.chrome.loadTimes != null),
 
2342
    isOpera:     (window.opera != null && window.opera.version != null),
 
2343
    isKonqueror: (window.hasOwnProperty && window.hasOwnProperty("konqueror") && navigator.vendor == "KDE"),
 
2344
    versionAtLeast: function (v) {
 
2345
      var bv = (this.version).split('.'); v = (new String(v)).split('.');
 
2346
      for (var i = 0, m = v.length; i < m; i++)
 
2347
        {if (bv[i] != v[i]) {return parseInt(bv[i]||"0") >= parseInt(v[i])}}
 
2348
      return true;
 
2349
    },
 
2350
    Select: function (choices) {
 
2351
      var browser = choices[HUB.Browser];
 
2352
      if (browser) {return browser(HUB.Browser)}
 
2353
      return null;
 
2354
    }
 
2355
  };
 
2356
 
 
2357
  var AGENT = navigator.userAgent
 
2358
    .replace(/^Mozilla\/(\d+\.)+\d+ /,"")                                   // remove initial Mozilla, which is never right
 
2359
    .replace(/[a-z][-a-z0-9._: ]+\/\d+[^ ]*-[^ ]*\.([a-z][a-z])?\d+ /i,"")  // remove linux version
 
2360
    .replace(/Gentoo |Ubuntu\/(\d+\.)*\d+ (\([^)]*\) )?/,"");               // special case for these
 
2361
 
 
2362
  HUB.Browser = HUB.Insert(HUB.Insert(new String("Unknown"),{version: "0.0"}),BROWSERS);
 
2363
  for (var browser in BROWSERS) {if (BROWSERS.hasOwnProperty(browser)) {
 
2364
    if (BROWSERS[browser] && browser.substr(0,2) === "is") {
 
2365
      browser = browser.slice(2);
 
2366
      if (browser === "Mac" || browser === "PC") continue;
 
2367
      HUB.Browser = HUB.Insert(new String(browser),BROWSERS);
 
2368
      var VERSION = new RegExp(
 
2369
        ".*(Version)/((?:\\d+\\.)+\\d+)|" +                                       // for Safari and Opera10
 
2370
        ".*("+browser+")"+(browser == "MSIE" ? " " : "/")+"((?:\\d+\\.)*\\d+)|"+  // for one of the main browser
 
2371
        "(?:^|\\(| )([a-z][-a-z0-9._: ]+|(?:Apple)?WebKit)/((?:\\d+\\.)+\\d+)");  // for unrecognized browser
 
2372
      var MATCH = VERSION.exec(AGENT) || ["","","","unknown","0.0"];
 
2373
      HUB.Browser.name = (MATCH[1] == "Version" ? browser : (MATCH[3] || MATCH[5]));
 
2374
      HUB.Browser.version = MATCH[2] || MATCH[4] || MATCH[6];
 
2375
      break;
 
2376
    }
 
2377
  }};
 
2378
  
 
2379
  //
 
2380
  //  Initial browser-specific info (e.g., touch up version or name)
 
2381
  //
 
2382
  HUB.Browser.Select({
 
2383
    Safari: function (browser) {
 
2384
      var v = parseInt((String(browser.version).split("."))[0]);
 
2385
      if (v > 85) {browser.webkit = browser.version}
 
2386
      if      (v >= 534) {browser.version = "5.1"}
 
2387
      else if (v >= 533) {browser.version = "5.0"}
 
2388
      else if (v >= 526) {browser.version = "4.0"}
 
2389
      else if (v >= 525) {browser.version = "3.1"}
 
2390
      else if (v >  500) {browser.version = "3.0"}
 
2391
      else if (v >  400) {browser.version = "2.0"}
 
2392
      else if (v >   85) {browser.version = "1.0"}
 
2393
      browser.isMobile = (navigator.appVersion.match(/Mobile/i) != null);
 
2394
      browser.noContextMenu = browser.isMobile;
 
2395
    },
 
2396
    Firefox: function (browser) {
 
2397
      if ((browser.version === "0.0" || navigator.userAgent.match(/Firefox/) == null) &&
 
2398
           navigator.product === "Gecko") {
 
2399
        var rv = navigator.userAgent.match(/[\/ ]rv:(\d+\.\d.*?)[\) ]/);
 
2400
        if (rv) {browser.version = rv[1]}
 
2401
        else {
 
2402
          var date = (navigator.buildID||navigator.productSub||"0").substr(0,8);
 
2403
          if      (date >= "20111220") {browser.version = "9.0"}
 
2404
          else if (date >= "20111120") {browser.version = "8.0"}
 
2405
          else if (date >= "20110927") {browser.version = "7.0"}
 
2406
          else if (date >= "20110816") {browser.version = "6.0"}
 
2407
          else if (date >= "20110621") {browser.version = "5.0"}
 
2408
          else if (date >= "20110320") {browser.version = "4.0"}
 
2409
          else if (date >= "20100121") {browser.version = "3.6"}
 
2410
          else if (date >= "20090630") {browser.version = "3.5"}
 
2411
          else if (date >= "20080617") {browser.version = "3.0"}
 
2412
          else if (date >= "20061024") {browser.version = "2.0"}
 
2413
        }
 
2414
      }
 
2415
      browser.isMobile = (navigator.appVersion.match(/Android/i) != null ||
 
2416
                          navigator.userAgent.match(/ Fennec\//) != null);
 
2417
    },
 
2418
    Opera: function (browser) {browser.version = opera.version()},
 
2419
    MSIE: function (browser) {
 
2420
      browser.isIE9 = !!(document.documentMode && (window.performance || window.msPerformance));
 
2421
      MathJax.HTML.setScriptBug = !browser.isIE9 || document.documentMode < 9;
 
2422
      var MathPlayer = false;
 
2423
      try {new ActiveXObject("MathPlayer.Factory.1"); browser.hasMathPlayer = MathPlayer = true}
 
2424
        catch (err) {}
 
2425
      try {
 
2426
        if (MathPlayer && !STARTUP.params.NoMathPlayer) {
 
2427
          var mathplayer = document.createElement("object");
 
2428
          mathplayer.id = "mathplayer"; mathplayer.classid = "clsid:32F66A20-7614-11D4-BD11-00104BD3F987";
 
2429
          document.getElementsByTagName("head")[0].appendChild(mathplayer);
 
2430
          document.namespaces.add("m","http://www.w3.org/1998/Math/MathML");
 
2431
          browser.mpNamespace = true;
 
2432
          if (document.readyState && (document.readyState === "loading" ||
 
2433
                                      document.readyState === "interactive")) {
 
2434
            document.write('<?import namespace="m" implementation="#MathPlayer">');
 
2435
            browser.mpImported = true;
 
2436
          }
 
2437
        } else {
 
2438
          //  Adding any namespace avoids a crash in IE9 in IE9-standards mode
 
2439
          //  (any reference to document.namespaces before document.readyState is 
 
2440
          //   "complete" causes an "unspecified error" to be thrown)
 
2441
          document.namespaces.add("mjx_IE_fix","http://www.w3.org/1999/xlink");
 
2442
        }
 
2443
      } catch (err) {}
 
2444
    }
 
2445
  });
 
2446
  HUB.Browser.Select(MathJax.Message.browsers);
 
2447
 
 
2448
  HUB.queue = BASE.Callback.Queue();
 
2449
  HUB.queue.Push(
 
2450
    ["Post",STARTUP.signal,"Begin"],
 
2451
    ["Config",STARTUP],
 
2452
    ["Cookie",STARTUP],
 
2453
    ["Styles",STARTUP],
 
2454
    ["Message",STARTUP],
 
2455
    function () {
 
2456
      // Do Jax and Extensions in parallel, but wait for them all to complete
 
2457
      var queue = BASE.Callback.Queue(
 
2458
        STARTUP.Jax(),
 
2459
        STARTUP.Extensions()
 
2460
      );
 
2461
      return queue.Push({});
 
2462
    },
 
2463
    ["Menu",STARTUP],
 
2464
    STARTUP.onLoad(),
 
2465
    function () {MathJax.isReady = true}, // indicates that MathJax is ready to process math
 
2466
    ["Typeset",STARTUP],
 
2467
    ["Hash",STARTUP],
 
2468
    ["MenuZoom",STARTUP],
 
2469
    ["Post",STARTUP.signal,"End"]
 
2470
  );
 
2471
  
 
2472
})("MathJax");
 
2473
 
 
2474
}}
 
2475
 
 
2476
/**********************************************************/