diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..20f2f09 --- /dev/null +++ b/Makefile @@ -0,0 +1,36 @@ +TOPDIR = ./ + +EXPORT_WIDTH = 1024 + +images_dia = $(wildcard figures/*.dia) +images_png = $(images_dia:.dia=.png) +datauris = code/hack-4/full.py.datauri \ + code/hack-5/full.py.datauri \ + code/hack-6.py.datauri \ + code/hack-7.py.datauri \ + code/hack-8.py.datauri + +code/hack-4/full.py.datauri: MIMETYPE="text/plain;charset=us-ascii" +code/hack-5/full.py.datauri: MIMETYPE="text/plain;charset=us-ascii" +code/hack-6.py.datauri: MIMETYPE="text/plain;charset=us-ascii" +code/hack-7.py.datauri: MIMETYPE="text/plain;charset=us-ascii" +code/hack-8.py.datauri: MIMETYPE="text/plain;charset=us-ascii" + +all: hack-4-split hack-5-split slides.html + +hack-4-split: + python $(TOPDIR)/scripts/split.py code/hack-4.py + +hack-5-split: + python $(TOPDIR)/scripts/split.py code/hack-5.py + +slides.html: $(images_png) $(datauris) + +clean: + rm -f $(images_png) + rm -f $(datauris) + rm -f slides.html + rm -fr code/hack-4 + rm -fr code/hack-5 + +include $(TOPDIR)/stylesheets/Makefile.rules diff --git a/code/hack-1.py b/code/hack-1.py new file mode 100644 index 0000000..fcbd9cb --- /dev/null +++ b/code/hack-1.py @@ -0,0 +1,4 @@ +def myfunc(): + return 6 / 2 + +print myfunc() diff --git a/code/hack-2.py b/code/hack-2.py new file mode 100644 index 0000000..1787c95 --- /dev/null +++ b/code/hack-2.py @@ -0,0 +1,10 @@ +def myfunc(): + return 6 / 2 + +co = myfunc.__code__ + +print "co_consts:", +print co.co_consts + +print "co_code:", +print repr(co.co_code) diff --git a/code/hack-3.py b/code/hack-3.py new file mode 100644 index 0000000..8751b9d --- /dev/null +++ b/code/hack-3.py @@ -0,0 +1,10 @@ +def myfunc(): + return 6 / 2 + +co = myfunc.__code__ + +print "co_consts:", co.co_consts +print "co_code:" + +for i, ch in enumerate(co.co_code): + print " %d: %02X" % (i, ord(ch)) diff --git a/code/hack-4.py b/code/hack-4.py new file mode 100644 index 0000000..615420f --- /dev/null +++ b/code/hack-4.py @@ -0,0 +1,27 @@ +### START: full.py +import dis + +### START: disas.py +def disas(code): + bcode = code.co_code + state = "opcode" + + for op in bcode: + op = ord(op) + if state == "opcode": + print hex(op), dis.opname[op] + if op > dis.HAVE_ARGUMENT: + state = "arg1" + elif state == "arg1": + print hex(op) + state = "arg2" + elif state == "arg2": + print hex(op) + state = "opcode" +### END: disas.py + +def myfunc(): + return 6 / 2 + +disas(myfunc.__code__) +### END: full.py diff --git a/code/hack-5.py b/code/hack-5.py new file mode 100644 index 0000000..6e21f6b --- /dev/null +++ b/code/hack-5.py @@ -0,0 +1,33 @@ +### START: full.py +### START: myfunc.py +def myfunc(): + return 6 / 2 +### END: myfunc.py + +# Modifying the code object +### START: hack.py +import new + +co = myfunc.__code__ +myconsts = (None, 10, 2) +co2 = new.code(co.co_argcount, + co.co_nlocals, + co.co_stacksize, + co.co_flags, + co.co_code, + myconsts, + co.co_names, + co.co_varnames, + co.co_filename, + co.co_name, + co.co_firstlineno, + co.co_lnotab) +### END: hack.py + +# Injecting the code object +### START: inject.py +myfunc.__code__ = co2 + +print myfunc() +### END: inject.py +### END: full.py diff --git a/code/hack-6.py b/code/hack-6.py new file mode 100644 index 0000000..2d98f60 --- /dev/null +++ b/code/hack-6.py @@ -0,0 +1,34 @@ +import dis + +def myfunc(): + return 6 / 2 + +# Hacking the code object + +co = myfunc.__code__ + +bcode = co.co_code +bcode = list(bcode) +bcode[6] = "\x17" +bcode = "".join(bcode) + +import new + +co2 = new.code(co.co_argcount, + co.co_nlocals, + co.co_stacksize, + co.co_flags, + bcode, + co.co_consts, + co.co_names, + co.co_varnames, + co.co_filename, + co.co_name, + co.co_firstlineno, + co.co_lnotab) + +# Injecting the modified code object + +myfunc.__code__ = co2 + +print myfunc() diff --git a/code/hack-7.py b/code/hack-7.py new file mode 100644 index 0000000..61b9794 --- /dev/null +++ b/code/hack-7.py @@ -0,0 +1,32 @@ +import new + +myconsts = (None, "Hello Byte Code World!") +mycode = ("\x64" # LOAD_CONST + "\x01" # 0x0001 + "\x00" # + "\x47" # PRINT_ITEM + "\x48" # PRINT_NEWLINE + "\x64" # LOAD_CONST + "\x00" # 0x0000 + "\x00" # + "\x53") # RETURN_VALUE + +# Create the code object +co = new.code(0, # co_argcount, + 0, # co_nlocals, + 1, # co_stacksize, + 0, # co_flags, + mycode, # co_code, + myconsts, # co_consts, + (), # co_names + (), # co_varnames + "test.py", # co_filename, + "myfunc", # co_name, + 0, # co_firstlineno, + "") # co_lnotab) + +# Create the function object +myfunc = new.function(co, {}) + +# Invoke the function +myfunc() diff --git a/code/hack-8.py b/code/hack-8.py new file mode 100644 index 0000000..cfef853 --- /dev/null +++ b/code/hack-8.py @@ -0,0 +1,30 @@ +import new + +myvarnames = ("a", "b") +mycode = ("\x7C" # LOAD_FAST + "\x00" # 0x0000 + "\x00" # + "\x7C" # LOAD_FAST + "\x01" # 0x0001 + "\x00" # + "\x17" # BINARY_ADD + "\x53") # RETURN_VALUE + +co = new.code(2, # co_argcount, + 2, # co_nlocals, + 2, # co_stacksize, + 0, # co_flags, + mycode, # co_code, + (), # co_consts, + (), # co_names + myvarnames,# co_varnames + "test.py", # co_filename, + "myfunc", # co_name, + 0, # co_firstlineno, + "") # co_lnotab + + +myfunc = new.function(co, {}) + +print "myfunc(10, 20) =>", myfunc(10, 20) +print 'myfunc("abc", "def") =>', myfunc("abc", "def") diff --git a/code/hack-9.py b/code/hack-9.py new file mode 100644 index 0000000..c28756b --- /dev/null +++ b/code/hack-9.py @@ -0,0 +1,29 @@ +myvarnames = ("a", "b") +mycode = ("\x7C" # LOAD_FAST + "\x00" # 0x0000 + "\x00" # + "\x7C" # LOAD_FAST + "\x01" # 0x0001 + "\x00" # + "\x17" # BINARY_ADD + "\x53") # RETURN_VALUE + +import new + +co = new.code(2, # co_argcount, + 2, # co_nlocals, + 2, # co_stacksize, + 0, # co_flags, + mycode, # co_code, + (), # co_consts, + (), # co_names + myvarnames,# co_varnames + "test.py", # co_filename, + "myfunc", # co_name, + 0, # co_firstlineno, + "") # co_lnotab + + +myfunc = new.function(co, {}) + +print myfunc("abc", "def") diff --git a/figures/lang-byte-code.dia b/figures/lang-byte-code.dia new file mode 100644 index 0000000..8405cb0 --- /dev/null +++ b/figures/lang-byte-code.dia @@ -0,0 +1,341 @@ + + + + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Source code# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Python Byte Code + +Purpose: Ease interpretation# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Java Byte Code + +Purpose: Reduce machine dependency# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Machine Code# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Instruction +Complexity# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/figures/locals.dia b/figures/locals.dia new file mode 100644 index 0000000..e2230bc --- /dev/null +++ b/figures/locals.dia @@ -0,0 +1,932 @@ + + + + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Python +Interpreter# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Heap# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #10# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #20# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #30# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #co_varnames# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #locals# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #"a"# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #"b"# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #"c"# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/figures/microprocessor-1.dia b/figures/microprocessor-1.dia new file mode 100644 index 0000000..eea5e64 --- /dev/null +++ b/figures/microprocessor-1.dia @@ -0,0 +1,397 @@ + + + + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Memory# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #CPU# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Read Data# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Write Data# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Instructions# + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/figures/microprocessor-2.dia b/figures/microprocessor-2.dia new file mode 100644 index 0000000..88166bc --- /dev/null +++ b/figures/microprocessor-2.dia @@ -0,0 +1,396 @@ + + + + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Memory# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #CPU# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Read Data# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Write Data# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Instructions# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/figures/microprocessor-3.dia b/figures/microprocessor-3.dia new file mode 100644 index 0000000..ae64d9b --- /dev/null +++ b/figures/microprocessor-3.dia @@ -0,0 +1,606 @@ + + + + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Memory# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #CPU# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Read Data# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Write Data# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Instructions# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Registers# + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/figures/module-autoload.dia b/figures/module-autoload.dia new file mode 100644 index 0000000..611dd7d --- /dev/null +++ b/figures/module-autoload.dia @@ -0,0 +1,911 @@ + + + + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Software# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Hardware# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Each device is +identified by + +Vendor ID +Product ID + +In addition, the +device might specify +a device class (Class ID), +like +input, ethernet, +VGA, etc + +All devices in a class, +have the same programming +interface# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #USB Controller# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Kernel# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #UDev# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Each kernel module +specifies a list +of devices it supports + +This information +is encoded in the +module information +as aliases. + +depmod creates +modules.alias file +using this info when +the module is +installed.# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Interrupt is raised +to indicate a device +hotplug# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #USB Subsystem, +enumerates the +devices and sends +the Vendor ID +and Product ID, +sends out a netlink +message with +MODALIAS variable.# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Modprobe# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Invokes modprobe +with MODALIAS as +argument# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Uses modules.alias +to load matching +modules +into the kernel.# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Module# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #USB Device# + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/figures/py-vm-1.dia b/figures/py-vm-1.dia new file mode 100644 index 0000000..bf913f5 --- /dev/null +++ b/figures/py-vm-1.dia @@ -0,0 +1,532 @@ + + + + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Heap# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Python +Interpreter# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Instructions# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Read +Objects# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Create, Modify +& Delete Objects# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + diff --git a/figures/py-vm-2.dia b/figures/py-vm-2.dia new file mode 100644 index 0000000..619cb01 --- /dev/null +++ b/figures/py-vm-2.dia @@ -0,0 +1,423 @@ + + + + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Heap# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Python +Interpreter# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #code +object# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + diff --git a/figures/py-vm-stack-1.dia b/figures/py-vm-stack-1.dia new file mode 100644 index 0000000..f31bd45 --- /dev/null +++ b/figures/py-vm-stack-1.dia @@ -0,0 +1,680 @@ + + + + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Python +Interpreter# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Heap# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Stack# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #10# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #20# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/figures/py-vm-stack-2.dia b/figures/py-vm-stack-2.dia new file mode 100644 index 0000000..65a020b --- /dev/null +++ b/figures/py-vm-stack-2.dia @@ -0,0 +1,689 @@ + + + + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Python +Interpreter# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Heap# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Stack# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #10# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #20# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #30# + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/figures/py-vm-stack-3.dia b/figures/py-vm-stack-3.dia new file mode 100644 index 0000000..7ef6e97 --- /dev/null +++ b/figures/py-vm-stack-3.dia @@ -0,0 +1,728 @@ + + + + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Heap# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #10# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #20# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #30# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Python +Interpreter# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Stack# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/figures/stack-machine-1.dia b/figures/stack-machine-1.dia new file mode 100644 index 0000000..a01a2ea --- /dev/null +++ b/figures/stack-machine-1.dia @@ -0,0 +1,348 @@ + + + + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # + loadi 1 + loadi 2 + add + loadi 4 + add +# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #1# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/figures/stack-machine-2.dia b/figures/stack-machine-2.dia new file mode 100644 index 0000000..bbab36c --- /dev/null +++ b/figures/stack-machine-2.dia @@ -0,0 +1,346 @@ + + + + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #1# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #2# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # + loadi 1 + loadi 2 + add + loadi 4 + add +# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/figures/stack-machine-3.dia b/figures/stack-machine-3.dia new file mode 100644 index 0000000..839dcfd --- /dev/null +++ b/figures/stack-machine-3.dia @@ -0,0 +1,346 @@ + + + + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #3# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # + loadi 1 + loadi 2 + add + loadi 4 + add +# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/figures/stack-machine-4.dia b/figures/stack-machine-4.dia new file mode 100644 index 0000000..1f749a5 --- /dev/null +++ b/figures/stack-machine-4.dia @@ -0,0 +1,346 @@ + + + + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #3# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # + loadi 1 + loadi 2 + add + loadi 4 + add +# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/figures/stack-machine-5.dia b/figures/stack-machine-5.dia new file mode 100644 index 0000000..85cb3b2 --- /dev/null +++ b/figures/stack-machine-5.dia @@ -0,0 +1,346 @@ + + + + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #7# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # + loadi 1 + loadi 2 + add + loadi 4 + add +# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/figures/stack-machine.dia b/figures/stack-machine.dia new file mode 100644 index 0000000..da2a56d --- /dev/null +++ b/figures/stack-machine.dia @@ -0,0 +1,1464 @@ + + + + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # + loadi 1 + loadi 2 + add + loadi 4 + add +# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #1# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #1# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #2# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #3# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #3# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #7# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # + loadi 1 + loadi 2 + add + loadi 4 + add +# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # + loadi 1 + loadi 2 + add + loadi 4 + add +# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # + loadi 1 + loadi 2 + add + loadi 4 + add +# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # + loadi 1 + loadi 2 + add + loadi 4 + add +# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/links.txt b/links.txt new file mode 100644 index 0000000..c17e90d --- /dev/null +++ b/links.txt @@ -0,0 +1,9 @@ +http://stackoverflow.com/questions/25594231/why-is-not-faster-than-bool-in-python-or-speed-of-python-functions-vs-s/25594345#25594345 +http://stackoverflow.com/questions/3815359/while-1-vs-for-whiletrue-why-is-there-a-difference +http://stackoverflow.com/questions/869229/why-is-looping-over-range-in-python-faster-than-using-a-while-loop/869347#869347 +http://stackoverflow.com/questions/34239159/cost-of-using-109-over-1000000000/34239211#34239211 +http://stackoverflow.com/questions/13047895/efficient-ways-to-duplicate-array-list-in-python/13048047#13048047 +http://stackoverflow.com/questions/37172464/python-local-variable-initialization/37172897#37172897 +http://stackoverflow.com/questions/22208987/why-is-the-use-of-e-n-for-creating-a-list-of-single-item-repeated-n-times/22209524#22209524 +http://stackoverflow.com/questions/664118/whats-the-difference-between-dict-and/664143#664143 +https://doughellmann.com/blog/2012/11/12/the-performance-impact-of-using-dict-instead-of-in-cpython-2-7-2/ diff --git a/microprocessor-1.dia b/microprocessor-1.dia new file mode 100644 index 0000000..eea5e64 --- /dev/null +++ b/microprocessor-1.dia @@ -0,0 +1,397 @@ + + + + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Memory# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #CPU# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Read Data# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Write Data# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Instructions# + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/microprocessor-1.png b/microprocessor-1.png new file mode 100644 index 0000000..5bd5418 Binary files /dev/null and b/microprocessor-1.png differ diff --git a/microprocessor-2.dia b/microprocessor-2.dia new file mode 100644 index 0000000..88166bc --- /dev/null +++ b/microprocessor-2.dia @@ -0,0 +1,396 @@ + + + + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Memory# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #CPU# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Read Data# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Write Data# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Instructions# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/microprocessor-2.png b/microprocessor-2.png new file mode 100644 index 0000000..38a2d20 Binary files /dev/null and b/microprocessor-2.png differ diff --git a/scripts/data-uri.py b/scripts/data-uri.py new file mode 100644 index 0000000..19ae28a --- /dev/null +++ b/scripts/data-uri.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +"""Command line script to convert a file, usually an image, into a data URI +for use on the web.""" + +import base64 +import os +import sys + + +class FileNotFoundError(Exception): + pass + + +def img_to_data(mime, path): + """Convert a file (specified by a path) into a data URI.""" + if not os.path.exists(path): + raise FileNotFoundError + with open(path, 'rb') as fp: + data = fp.read() + data64 = u''.join(base64.encodestring(data).splitlines()) + return u'data:%s;base64,%s' % (mime, data64) + + +def usage(argv): + print 'Usage: %s ' % argv[0] + + +if __name__ == '__main__': + try: + mimetype = sys.argv[1] + path = sys.argv[2] + except IndexError: + usage(sys.argv) + sys.exit(1) + + try: + print img_to_data(mimetype, path) + except FileNotFoundError: + print 'File not found!' + sys.exit(2) diff --git a/scripts/split.py b/scripts/split.py new file mode 100644 index 0000000..135084c --- /dev/null +++ b/scripts/split.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +""" +Usage: split.py + +Splits the file into parts and stores them under a directory called +`filename` (the input filename with extension stripped). + +Each part to be split should be delimited by patterns shown below. + +### START: part-filename +... +content +... +### END: part-filename + +The `content` will be stored within the directory in a file called +`part-filename`. +""" + +from __future__ import print_function + +import re +import sys +import os +import os.path + + +start_regex = re.compile("### START: ([-.a-z0-9]*)") +end_regex = re.compile("### END: ([-.a-z0-9]*)") + + +def get_starts_ends(script): + starts = {} + ends = {} + + for lineno, line in enumerate(script): + match = start_regex.search(line) + if match: + filename = match.group(1) + starts[filename] = lineno + + match = end_regex.search(line) + if match: + filename = match.group(1) + ends[filename] = lineno + + return (starts, ends) + + +def write_part(part_filename, script, start_lineno, end_lineno): + with open(part_filename, "w") as fp: + for line in range(start_lineno + 1, end_lineno): + text = script[line] + if not (start_regex.search(text) or end_regex.search(text)): + fp.write(script[line]) + + +def split(script_filename, script): + starts, ends = get_starts_ends(script) + + start_filenames = set(starts.keys()) + end_filenames = set(ends.keys()) + + if start_filenames != end_filenames: + print("Unmatched START and END:", + start_filenames ^ end_filenames) + sys.exit(1) + + root, ext = os.path.splitext(script_filename) + if os.path.exists(root): + if not os.path.isdir(root): + print("File {0} is in the way".format(root)) + sys.exit(1) + else: + os.mkdir(root) + + for filename in start_filenames: + start_lineno = starts[filename] + end_lineno = ends[filename] + write_part(os.path.join(root, filename), + script, start_lineno, end_lineno) + + +def main(script_filename): + with open(script_filename) as fp: + script = fp.readlines() + + split(script_filename, script) + + +if __name__ == "__main__": + if len(sys.argv) != 2: + print(__doc__) + + main(sys.argv[1]) diff --git a/slides.asciidoc b/slides.asciidoc new file mode 100644 index 0000000..65dfa4b --- /dev/null +++ b/slides.asciidoc @@ -0,0 +1,611 @@ += Python Byte Code Hacks +Vijay Kumar +:data-uri: + +=== Overview + + * Python VM + - Process Virtual Machines + - Stack vs Register Machines + - Python's Stack Machines + + * Byte Code Hacks + - Code Objects + - Modifying Code Objects + - Handcrafted Code Objects + +== Python VM + +=== Compilers & Interpreters + + * C -- compiler converts C source to machine instructions + + * GW-BASIC, the programs were interpreted line by line + + * Python and Java + + - source code is compiled to a intermediate language byte codes + - byte codes are then executed by an interpreter + +=== Java vs Python + + * Java, source code is compiled to byte code + - to reduce machine dependency + - to increasing portability + + * Python, the source code is compiled to byte code + - to reduce parsing overhead + - to ease interpretation. + +=== Program Representation + +image::figures/lang-byte-code.png[align="center",width="60%"] + +=== What are Virtual Machines? + +______ +Software that executes the byte code is called the abstract virtual +machine. These virtual machines are modelled after microprocessors. +______ + +=== Microprocessor Model v1 + +image::figures/microprocessor-1.png[align="center",width="50%"] + + * A microprocessor is a device that reads data from memory, + processes it and writes back data to memory, based on instructions + +=== Microprocessor Model v1 + +image::figures/microprocessor-1.png[align="center",width="50%"] + + * Instructions specify, memory location to read operands from, + operation to perform, memory location to write the result to + +=== Microprocessor Model v2 + +image::figures/microprocessor-2.png[align="center",width="50%"] + + * Improvised model of microprocessor + + * Instructions are themselves stored in memory + +=== Microprocessor Model v2 + +image::figures/microprocessor-2.png[align="center",width="50%"] + + * A microprocessor is a device that reads data from memory, + processes it and writes back data to memory, based on + instructions, which are themselves stored / fetched from memory." + +=== Microprocessor Model v3 + +image::figures/microprocessor-3.png[align="center",width="50%"] + + * Registers: memory locations within microprocessors + * Operands and results are temporarily stored in registers + +=== Python Interpreter Model v1 + +image::figures/py-vm-1.png[align="center",width="50%"] + + * Modelled after microprocessors. Data is represented as objects + stored in the heap + + * Works by manipulating these objects in memory, based on + instructions + +=== Python Interpreter Model v1 + +image::figures/py-vm-1.png[align="center",width="50%"] + + * Instructions specify the type of objects to create, which objects + to delete, the attribute of an object to be read / modified. + +=== Python Interpreter Model v2 + +image::figures/py-vm-2.png[align="center",width="50%"] + + * Byte code instructions are themselves wrapped in "code objects" + and are also stored in the heap + +=== Python Interpreter Model v2 + +image::figures/py-vm-2.png[align="center",width="50%"] + + * Python's compiler, parses functions / modules, converts them to code objects + + * Python interpreter executes the code objects + +=== Types of Virtual Machines + + * Classification depending on how the operands are accessed and + results are stored, by instructions + + * Types of Abstract Virtual Machines + + 1. Register Machines + 2. Stack Machines + +=== Register Machines + + * Register machines are more like traditional microprocessors + + * Expression: `1 + 2 + 4` ++ +------ +LOADK R1, 1 +LOADK R2, 2 +ADD R3, R2, R1 # R3 = R2 + R1 +LOADK R1, 4 +ADD R3, R3, R1 # R3 = R3 + R1 +------ ++ + * Examples: + - Lua VM + - Dalvick VM + +=== Stack Machines + + * Instructions, for a hypothetical stack machine ++ +------ +loadi 1 +loadi 2 +add +loadi 4 +add +------ + +=== Step 1 + +image::figures/stack-machine-1.png[align="center",width="12%"] + +=== Step 2 + +image::figures/stack-machine-2.png[align="center",width="12%"] + +=== Step 3 + +image::figures/stack-machine-3.png[align="center",width="12%"] + +=== Step 4 + +image::figures/stack-machine-4.png[align="center",width="12%"] + +=== Step 5 + +image::figures/stack-machine-5.png[align="center",width="12%"] + +=== Python's Stack Machine: Difference + + * Objects are always stored in the heap + * Only the pointer to the object is stored in the stack + * Operation of `BINARY_ADD` instruction + +=== Step 1: Initial State + +image::figures/py-vm-stack-1.png[align="center",width="60%"] + + * Two integer objects in the heap, stack has pointers to the two + objects + +=== Step 2: Add the Stack Operands + +image::figures/py-vm-stack-2.png[align="center",width="60%"] + + * Pops off the top two objects `10` and `20`, adds them resulting in + a new object `30` + +=== Step 3: Final State + +image::figures/py-vm-stack-3.png[align="center",width="60%"] + + * Pushes the pointer to the object on to the stack + +== Byte Code Hacks + +=== Getting Started + +[source,python] +------- +include::code/hack-1.py[] +------- + +The function just divides two constants and returns the value back to +the caller. + +[role="two-column"] +=== The Code Object + +[role="left"] +[source,python] +------ +include::code/hack-2.py[] +------ + +[role="right"] + * Code object is accessible from `myfunc.__code__`. + + * `co_consts`, contains a tuple of constants used by the function. + + * `co_code`, contains the byte code instructions, generated by + compiling the function + +[role="two-column"] +=== The Code Object + +[role="left"] +[source,python] +------ +include::code/hack-2.py[] +------ + +[role="right"] + * Code object associated with every function + + * Contains the byte code instructions and associated data to execute + the function + +=== What does `0x64` mean? + + * `dis` module has a mapping from opcodes to mnemonics ++ +[source,python] +------ +>>> import dis +>>> print dis.opname[0x64] +------ + +=== `LOAD_CONST` Instruction + + * Followed by 2 byte integer operand + + * Operand is an index into the `co_const` tuple + + * Specifies the constant to be pushed / loaded into the stack + + * Operand specified in this case `0x0001`, corresponds to the + constant `6` + + * Instruction can thus be represented in mnemonics as ++ +------ +LOAD_CONST 1 +------ + +=== Second Instruction + +------ +co_consts: (None, 6, 2) +co_code: + 0: 64 + 1: 01 + 2: 00 + 3: 64 <= + 4: 02 + 5: 00 + 6: 15 + 7: 53 +------ + + * Second instruction is `LOAD_CONST` + + * Operand is the index `0x0002`, which corresponds to the constant + `2` + +=== Decoded Instructions + + * Instructions decoded so far ++ +------ +64 LOAD_CONST 1 +01 +00 +64 LOAD_CONST 2 +02 +00 +------ + +=== Third Instruction + +------ +co_consts: (None, 6, 2) +co_code: + 0: 64 + 1: 01 + 2: 00 + 3: 64 + 4: 02 + 5: 00 + 6: 15 <= + 7: 53 +------ + +------ +>>> print dis.opname[0x15] +------ + +=== `BINARY_DIVIDE` Instruction + + * Does not require any operands + + * Pops top two values from the stack, and performs a divide and + pushes the result back on to the stack + +=== Fourth Instruction + +------ +co_consts: (None, 6, 2) +co_code: + 0: 64 + 1: 01 + 2: 00 + 3: 64 + 4: 02 + 5: 00 + 6: 15 + 7: 53 <= +------ + +------ +>>> print dis.opname[0x53] +------ + +=== `RETURN_VALUE` Instruction + + * `RETURN_VALUE` instruction takes the top of the stack and returns + the value back to the caller. + +=== Complete Dis-assembly + +------ +64 LOAD_CONST 1 +01 +00 +64 LOAD_CONST 2 +02 +00 +15 BINARY_DIVIDE +53 RETURN_VALUE +------ + +=== Writing a Dis-assembler + + * Manual dis-assembly of code + * A disassembler runs through byte code string + - prints the `opname` of the each byte code instruction + * Only catch is that _some_ of them take an operand + +=== Writing a Dis-assembler (Contd.) + + * Code to determine if an opcode takes an operand ++ +[source,python] +------ +if op > dis.HAVE_ARGUMENT: + print "opcode has an operand." +else: + print "opcode does not have an operand." +------ ++ + * link:{include:code/hack-4/full.py.datauri}["Get disas.py",filename="disas.py"] + +=== Built-in Disassembler + +The `dis` module has a `disassemble()` function: + +[source,python] +------ +>>> help(dis.disassemble) +Help on function disassemble in module dis: + +disassemble(co, lasti=-1) + Disassemble a code object. +------ + +== Hack 1 + +=== Hacking Code Objects + + * Modify the constants so that the tuple is `(None, 10, 2)` instead + of `(None, 6, 2)` + + * Will that result in the program printing `5`? + + * But code objects are immutable + + * Create a new code object with the new value for `co_consts` + + * link:{include:code/hack-5/full.py.datauri}["Get hack-1.py",filename="hack-1.py"] + +[role="two-column"] +=== Hack Explained + +[role="left"] +[source,python] +------ +include::code/hack-5/hack.py[] +------ + +[role="right"] + * `new` module has the constructor to create the code objects + + * Takes a huge list of arguments + + * All arguments are specified from the old code object, except for the `co_consts` + + * A new set of constants is specified instead + +[role="two-column"] +=== Hack Explained + +[role="left"] +[source,python] +------ +include::code/hack-5/inject.py[] +------ + +[role="right"] + * Old code object is replaced with new code object + +== Hack 2 + +=== Hacking the Byte Code String + + * Modify the byte code string + * Replace the `BINARY_DIVIDE` instruction with `BINARY_ADD` + * `BINARY_ADD` corresponds to opcode `0x17` + * `BINARY_DIVIDE` appears at offset 6 is the byte code string + * Need to replace it with `BINARY_ADD` + +=== `BINARY_DIVIDE` to `BINARY_ADD` + + * Code to unpack, modify and repack the byte code string ++ +[source,python] +------ +bcode = co.co_code # \x64\x01\x00\x64\x02\x00\x15\x53 +bcode = list(bcode) # ['\x64', '\x01', ..., '\x15', '\x53'] +bcode[6] = "\x17" +bcode = "".join(bcode) # \x64\x01\x00\x64\x02\x00\x17\x53 +------ ++ + * link:{include:code/hack-6.py.datauri}["Get hack-2.py",filename="hack-2.py"] + +== Hack 3 + +=== Look Ma, No Hands! + + * Create code object for a function, without actually writing the Python function + * Let's implement the classic "Hello World" + * Byte code instructions and the constants tuple for implementing this ++ +------ +Consts: (None, "Hello Byte Code World!") +Byte Code Instructions: + LOAD_CONST 1 + PRINT_ITEM + PRINT_NEWLINE + LOAD_CONST 0 + RETURN_VALUE +------ + +=== Instructions Explained + + * `PRINT_ITEM` pops object from the top of the stack and prints it + + * `PRINT_NEWLINE`, prints an newline character + + * Code returns `None`, to the caller, as required by Python + + * link:{include:code/hack-7.py.datauri}["Get hack-3.py",filename="hack-3.py"] + +=== Code Object Constructor + + * `co_argcount` + - Specifies the number of positional arguments + - Our value is `0` + + * `co_nlocals` + - Specifies the number of local variables, including positional arguments + - Our value is `0` + + * `co_stacksize` + - Specifies stack depth utilized by the code object + - At any given point, we do not store more than 1 element in the stack + +=== Code Object Constructor (Contd.) + + * `co_flags` + - Specifies using bit flags whether the function accepts variable + number of arguments, whether the function is a generator, etc. + + * `co_varnames` + - Specifies the names of positional arguments and local variables + - Empty tuple + + * `co_names` + - Specifies the names of identifiers other than local variables + - Empty tuple + +=== Code Object Constructor (Contd.) + + * `co_filename` + - Specifies the file in which the function was present + - Dummy filename `test.py` + + * `co_name` + - Specifies the name of the function. + + * `co_firstlineno` + - Specifies the first line number of the function within the file + +=== Code Object Constructor (Contd.) + + * `co_lnotab` + - Encodes the mapping of byte code offset to line numbers + - Used while printing tracebacks + - Empty string + +== Hack 4 + +=== More Bytes of Code + + * A Python function, that will accept two arguments, add them and + return the result + + * The byte code equivalent of the following Python function ++ +[source,python] +------ +def myfunc(a, b): + return a + b +------ + +=== `LOAD_FAST` Instruction + + * Arguments / local variables, can be loaded using `LOAD_FAST` + * Loads the value of a local variable on to the stack + * Instruction accepts an argument that specifies the local variable + as an index into the `co_varnames` tuple. + * link:{include:code/hack-8.py.datauri}["Get hack-4.py",filename="hack-4.py"] ++ +------ +Var Names: ("a", "b") +Byte Code: + LOAD_FAST 0 + LOAD_FAST 1 + BINARY_ADD + RETURN_VALUE +------ + +=== Code Object Constructor + + * No. of arguments, `co_argcount`, is `2` + * No. of arguments and local variables `co_nlocals`, is `2` + * Stack size `co_stacksize`, is specified as 2 + - A maximum of two items is pushed into the stack. + * Names of the positional arguments / local variables `co_varnames`, + is `("a", "b")` + +== Python vs Java + +=== Python Byte Code Instructions + + * `BINARY_ADD` instruction + - Does not operate on integers + - Unlike the `ADD` instruction of a microprocessor + - Operates on objects, provided they implement the `__add__()` or + `__radd__()` magic methods + + * Distinguishes Python's byte codes from Java's byte codes + * Python's byte codes are there to simplify interpretation + * More closer to the source language + +=== Java Byte Code Instructions + + * Java's byte codes are there to reduce machine dependency + * Are more closer to the machine instructions + +== Thank You \ No newline at end of file diff --git a/stylesheets/Makefile b/stylesheets/Makefile new file mode 100644 index 0000000..d5e723b --- /dev/null +++ b/stylesheets/Makefile @@ -0,0 +1,2 @@ +$(dl-files): + wget $@ $(dl-$( diff --git a/stylesheets/Makefile.rules b/stylesheets/Makefile.rules new file mode 100644 index 0000000..291f752 --- /dev/null +++ b/stylesheets/Makefile.rules @@ -0,0 +1,18 @@ +# -*- makefile -*- + +%.png: png_log_tmp := $(shell mktemp) +%.png: %.dia + dia --filter=png-libart $(and $(EXPORT_WIDTH),--size=$(EXPORT_WIDTH)) --export=$@ $< 2> $(png_log_tmp) + @trap "rm -f $(png_log_tmp)" EXIT; if grep Error $(png_log_tmp); then exit 1; else exit 0; fi + +%.html: %.asciidoc + asciidoc -f $(TOPDIR)/stylesheets/zslide.conf $< + +%.datauri: % + python $(TOPDIR)/scripts/data-uri.py $(MIMETYPE) $< > $@ + +install-extra: + +install: + mkdir $(TOPDIR)/build/$(notdir $(shell pwd)) + cp slides.html $(TOPDIR)/build/$(notdir $(shell pwd)) diff --git a/stylesheets/a.c b/stylesheets/a.c new file mode 100644 index 0000000..e69de29 diff --git a/stylesheets/javascripts/ASCIIMathML.js b/stylesheets/javascripts/ASCIIMathML.js new file mode 100644 index 0000000..489b312 --- /dev/null +++ b/stylesheets/javascripts/ASCIIMathML.js @@ -0,0 +1,938 @@ +/* +ASCIIMathML.js +============== +This file contains JavaScript functions to convert ASCII math notation +to Presentation MathML. The conversion is done while the (X)HTML page +loads, and should work with Firefox/Mozilla/Netscape 7+ and Internet +Explorer 6+MathPlayer (http://www.dessci.com/en/products/mathplayer/). +Just add the next line to your (X)HTML page with this file in the same folder: +This is a convenient and inexpensive solution for authoring MathML. + +Version 1.4.7 Dec 15, 2005, (c) Peter Jipsen http://www.chapman.edu/~jipsen +Latest version at http://www.chapman.edu/~jipsen/mathml/ASCIIMathML.js +For changes see http://www.chapman.edu/~jipsen/mathml/asciimathchanges.txt +If you use it on a webpage, please send the URL to jipsen@chapman.edu + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License (at http://www.gnu.org/copyleft/gpl.html) +for more details. +*/ + +var checkForMathML = true; // check if browser can display MathML +var notifyIfNoMathML = true; // display note if no MathML capability +var alertIfNoMathML = false; // show alert box if no MathML capability +var mathcolor = ""; // change it to "" (to inherit) or any other color +var mathfontfamily = "serif"; // change to "" to inherit (works in IE) + // or another family (e.g. "arial") +var displaystyle = true; // puts limits above and below large operators +var showasciiformulaonhover = true; // helps students learn ASCIIMath +var decimalsign = "."; // change to "," if you like, beware of `(1,2)`! +var AMdelimiter1 = "`", AMescape1 = "\\\\`"; // can use other characters +var AMdelimiter2 = "$", AMescape2 = "\\\\\\$", AMdelimiter2regexp = "\\$"; +var doubleblankmathdelimiter = false; // if true, x+1 is equal to `x+1` + // for IE this works only in +//var separatetokens;// has been removed (email me if this is a problem) +var isIE = document.createElementNS==null; + +if (document.getElementById==null) + alert("This webpage requires a recent browser such as\ +\nMozilla/Netscape 7+ or Internet Explorer 6+MathPlayer") + +// all further global variables start with "AM" + +function AMcreateElementXHTML(t) { + if (isIE) return document.createElement(t); + else return document.createElementNS("http://www.w3.org/1999/xhtml",t); +} + +function AMnoMathMLNote() { + var nd = AMcreateElementXHTML("h3"); + nd.setAttribute("align","center") + nd.appendChild(AMcreateElementXHTML("p")); + nd.appendChild(document.createTextNode("To view the ")); + var an = AMcreateElementXHTML("a"); + an.appendChild(document.createTextNode("ASCIIMathML")); + an.setAttribute("href","http://www.chapman.edu/~jipsen/asciimath.html"); + nd.appendChild(an); + nd.appendChild(document.createTextNode(" notation use Internet Explorer 6+")); + an = AMcreateElementXHTML("a"); + an.appendChild(document.createTextNode("MathPlayer")); + an.setAttribute("href","http://www.dessci.com/en/products/mathplayer/download.htm"); + nd.appendChild(an); + nd.appendChild(document.createTextNode(" or Netscape/Mozilla/Firefox")); + nd.appendChild(AMcreateElementXHTML("p")); + return nd; +} + +function AMisMathMLavailable() { + if (navigator.appName.slice(0,8)=="Netscape") + if (navigator.appVersion.slice(0,1)>="5") return null; + else return AMnoMathMLNote(); + else if (navigator.appName.slice(0,9)=="Microsoft") + try { + var ActiveX = new ActiveXObject("MathPlayer.Factory.1"); + return null; + } catch (e) { + return AMnoMathMLNote(); + } + else return AMnoMathMLNote(); +} + +// character lists for Mozilla/Netscape fonts +var AMcal = [0xEF35,0x212C,0xEF36,0xEF37,0x2130,0x2131,0xEF38,0x210B,0x2110,0xEF39,0xEF3A,0x2112,0x2133,0xEF3B,0xEF3C,0xEF3D,0xEF3E,0x211B,0xEF3F,0xEF40,0xEF41,0xEF42,0xEF43,0xEF44,0xEF45,0xEF46]; +var AMfrk = [0xEF5D,0xEF5E,0x212D,0xEF5F,0xEF60,0xEF61,0xEF62,0x210C,0x2111,0xEF63,0xEF64,0xEF65,0xEF66,0xEF67,0xEF68,0xEF69,0xEF6A,0x211C,0xEF6B,0xEF6C,0xEF6D,0xEF6E,0xEF6F,0xEF70,0xEF71,0x2128]; +var AMbbb = [0xEF8C,0xEF8D,0x2102,0xEF8E,0xEF8F,0xEF90,0xEF91,0x210D,0xEF92,0xEF93,0xEF94,0xEF95,0xEF96,0x2115,0xEF97,0x2119,0x211A,0x211D,0xEF98,0xEF99,0xEF9A,0xEF9B,0xEF9C,0xEF9D,0xEF9E,0x2124]; + +var CONST = 0, UNARY = 1, BINARY = 2, INFIX = 3, LEFTBRACKET = 4, + RIGHTBRACKET = 5, SPACE = 6, UNDEROVER = 7, DEFINITION = 8, + LEFTRIGHT = 9, TEXT = 10; // token types + +var AMsqrt = {input:"sqrt", tag:"msqrt", output:"sqrt", tex:null, ttype:UNARY}, + AMroot = {input:"root", tag:"mroot", output:"root", tex:null, ttype:BINARY}, + AMfrac = {input:"frac", tag:"mfrac", output:"/", tex:null, ttype:BINARY}, + AMdiv = {input:"/", tag:"mfrac", output:"/", tex:null, ttype:INFIX}, + AMover = {input:"stackrel", tag:"mover", output:"stackrel", tex:null, ttype:BINARY}, + AMsub = {input:"_", tag:"msub", output:"_", tex:null, ttype:INFIX}, + AMsup = {input:"^", tag:"msup", output:"^", tex:null, ttype:INFIX}, + AMtext = {input:"text", tag:"mtext", output:"text", tex:null, ttype:TEXT}, + AMmbox = {input:"mbox", tag:"mtext", output:"mbox", tex:null, ttype:TEXT}, + AMquote = {input:"\"", tag:"mtext", output:"mbox", tex:null, ttype:TEXT}; + +var AMsymbols = [ +//some greek symbols +{input:"alpha", tag:"mi", output:"\u03B1", tex:null, ttype:CONST}, +{input:"beta", tag:"mi", output:"\u03B2", tex:null, ttype:CONST}, +{input:"chi", tag:"mi", output:"\u03C7", tex:null, ttype:CONST}, +{input:"delta", tag:"mi", output:"\u03B4", tex:null, ttype:CONST}, +{input:"Delta", tag:"mo", output:"\u0394", tex:null, ttype:CONST}, +{input:"epsi", tag:"mi", output:"\u03B5", tex:"epsilon", ttype:CONST}, +{input:"varepsilon", tag:"mi", output:"\u025B", tex:null, ttype:CONST}, +{input:"eta", tag:"mi", output:"\u03B7", tex:null, ttype:CONST}, +{input:"gamma", tag:"mi", output:"\u03B3", tex:null, ttype:CONST}, +{input:"Gamma", tag:"mo", output:"\u0393", tex:null, ttype:CONST}, +{input:"iota", tag:"mi", output:"\u03B9", tex:null, ttype:CONST}, +{input:"kappa", tag:"mi", output:"\u03BA", tex:null, ttype:CONST}, +{input:"lambda", tag:"mi", output:"\u03BB", tex:null, ttype:CONST}, +{input:"Lambda", tag:"mo", output:"\u039B", tex:null, ttype:CONST}, +{input:"mu", tag:"mi", output:"\u03BC", tex:null, ttype:CONST}, +{input:"nu", tag:"mi", output:"\u03BD", tex:null, ttype:CONST}, +{input:"omega", tag:"mi", output:"\u03C9", tex:null, ttype:CONST}, +{input:"Omega", tag:"mo", output:"\u03A9", tex:null, ttype:CONST}, +{input:"phi", tag:"mi", output:"\u03C6", tex:null, ttype:CONST}, +{input:"varphi", tag:"mi", output:"\u03D5", tex:null, ttype:CONST}, +{input:"Phi", tag:"mo", output:"\u03A6", tex:null, ttype:CONST}, +{input:"pi", tag:"mi", output:"\u03C0", tex:null, ttype:CONST}, +{input:"Pi", tag:"mo", output:"\u03A0", tex:null, ttype:CONST}, +{input:"psi", tag:"mi", output:"\u03C8", tex:null, ttype:CONST}, +{input:"Psi", tag:"mi", output:"\u03A8", tex:null, ttype:CONST}, +{input:"rho", tag:"mi", output:"\u03C1", tex:null, ttype:CONST}, +{input:"sigma", tag:"mi", output:"\u03C3", tex:null, ttype:CONST}, +{input:"Sigma", tag:"mo", output:"\u03A3", tex:null, ttype:CONST}, +{input:"tau", tag:"mi", output:"\u03C4", tex:null, ttype:CONST}, +{input:"theta", tag:"mi", output:"\u03B8", tex:null, ttype:CONST}, +{input:"vartheta", tag:"mi", output:"\u03D1", tex:null, ttype:CONST}, +{input:"Theta", tag:"mo", output:"\u0398", tex:null, ttype:CONST}, +{input:"upsilon", tag:"mi", output:"\u03C5", tex:null, ttype:CONST}, +{input:"xi", tag:"mi", output:"\u03BE", tex:null, ttype:CONST}, +{input:"Xi", tag:"mo", output:"\u039E", tex:null, ttype:CONST}, +{input:"zeta", tag:"mi", output:"\u03B6", tex:null, ttype:CONST}, + +//binary operation symbols +{input:"*", tag:"mo", output:"\u22C5", tex:"cdot", ttype:CONST}, +{input:"**", tag:"mo", output:"\u22C6", tex:"star", ttype:CONST}, +{input:"//", tag:"mo", output:"/", tex:null, ttype:CONST}, +{input:"\\\\", tag:"mo", output:"\\", tex:"backslash", ttype:CONST}, +{input:"setminus", tag:"mo", output:"\\", tex:null, ttype:CONST}, +{input:"xx", tag:"mo", output:"\u00D7", tex:"times", ttype:CONST}, +{input:"-:", tag:"mo", output:"\u00F7", tex:"divide", ttype:CONST}, +{input:"@", tag:"mo", output:"\u2218", tex:"circ", ttype:CONST}, +{input:"o+", tag:"mo", output:"\u2295", tex:"oplus", ttype:CONST}, +{input:"ox", tag:"mo", output:"\u2297", tex:"otimes", ttype:CONST}, +{input:"o.", tag:"mo", output:"\u2299", tex:"odot", ttype:CONST}, +{input:"sum", tag:"mo", output:"\u2211", tex:null, ttype:UNDEROVER}, +{input:"prod", tag:"mo", output:"\u220F", tex:null, ttype:UNDEROVER}, +{input:"^^", tag:"mo", output:"\u2227", tex:"wedge", ttype:CONST}, +{input:"^^^", tag:"mo", output:"\u22C0", tex:"bigwedge", ttype:UNDEROVER}, +{input:"vv", tag:"mo", output:"\u2228", tex:"vee", ttype:CONST}, +{input:"vvv", tag:"mo", output:"\u22C1", tex:"bigvee", ttype:UNDEROVER}, +{input:"nn", tag:"mo", output:"\u2229", tex:"cap", ttype:CONST}, +{input:"nnn", tag:"mo", output:"\u22C2", tex:"bigcap", ttype:UNDEROVER}, +{input:"uu", tag:"mo", output:"\u222A", tex:"cup", ttype:CONST}, +{input:"uuu", tag:"mo", output:"\u22C3", tex:"bigcup", ttype:UNDEROVER}, + +//binary relation symbols +{input:"!=", tag:"mo", output:"\u2260", tex:"ne", ttype:CONST}, +{input:":=", tag:"mo", output:":=", tex:null, ttype:CONST}, +{input:"lt", tag:"mo", output:"<", tex:null, ttype:CONST}, +{input:"<=", tag:"mo", output:"\u2264", tex:"le", ttype:CONST}, +{input:"lt=", tag:"mo", output:"\u2264", tex:"leq", ttype:CONST}, +{input:">=", tag:"mo", output:"\u2265", tex:"ge", ttype:CONST}, +{input:"geq", tag:"mo", output:"\u2265", tex:null, ttype:CONST}, +{input:"-<", tag:"mo", output:"\u227A", tex:"prec", ttype:CONST}, +{input:"-lt", tag:"mo", output:"\u227A", tex:null, ttype:CONST}, +{input:">-", tag:"mo", output:"\u227B", tex:"succ", ttype:CONST}, +{input:"-<=", tag:"mo", output:"\u2AAF", tex:"preceq", ttype:CONST}, +{input:">-=", tag:"mo", output:"\u2AB0", tex:"succeq", ttype:CONST}, +{input:"in", tag:"mo", output:"\u2208", tex:null, ttype:CONST}, +{input:"!in", tag:"mo", output:"\u2209", tex:"notin", ttype:CONST}, +{input:"sub", tag:"mo", output:"\u2282", tex:"subset", ttype:CONST}, +{input:"sup", tag:"mo", output:"\u2283", tex:"supset", ttype:CONST}, +{input:"sube", tag:"mo", output:"\u2286", tex:"subseteq", ttype:CONST}, +{input:"supe", tag:"mo", output:"\u2287", tex:"supseteq", ttype:CONST}, +{input:"-=", tag:"mo", output:"\u2261", tex:"equiv", ttype:CONST}, +{input:"~=", tag:"mo", output:"\u2245", tex:"cong", ttype:CONST}, +{input:"~~", tag:"mo", output:"\u2248", tex:"approx", ttype:CONST}, +{input:"prop", tag:"mo", output:"\u221D", tex:"propto", ttype:CONST}, + +//logical symbols +{input:"and", tag:"mtext", output:"and", tex:null, ttype:SPACE}, +{input:"or", tag:"mtext", output:"or", tex:null, ttype:SPACE}, +{input:"not", tag:"mo", output:"\u00AC", tex:"neg", ttype:CONST}, +{input:"=>", tag:"mo", output:"\u21D2", tex:"implies", ttype:CONST}, +{input:"if", tag:"mo", output:"if", tex:null, ttype:SPACE}, +{input:"<=>", tag:"mo", output:"\u21D4", tex:"iff", ttype:CONST}, +{input:"AA", tag:"mo", output:"\u2200", tex:"forall", ttype:CONST}, +{input:"EE", tag:"mo", output:"\u2203", tex:"exists", ttype:CONST}, +{input:"_|_", tag:"mo", output:"\u22A5", tex:"bot", ttype:CONST}, +{input:"TT", tag:"mo", output:"\u22A4", tex:"top", ttype:CONST}, +{input:"|--", tag:"mo", output:"\u22A2", tex:"vdash", ttype:CONST}, +{input:"|==", tag:"mo", output:"\u22A8", tex:"models", ttype:CONST}, + +//grouping brackets +{input:"(", tag:"mo", output:"(", tex:null, ttype:LEFTBRACKET}, +{input:")", tag:"mo", output:")", tex:null, ttype:RIGHTBRACKET}, +{input:"[", tag:"mo", output:"[", tex:null, ttype:LEFTBRACKET}, +{input:"]", tag:"mo", output:"]", tex:null, ttype:RIGHTBRACKET}, +{input:"{", tag:"mo", output:"{", tex:null, ttype:LEFTBRACKET}, +{input:"}", tag:"mo", output:"}", tex:null, ttype:RIGHTBRACKET}, +{input:"|", tag:"mo", output:"|", tex:null, ttype:LEFTRIGHT}, +//{input:"||", tag:"mo", output:"||", tex:null, ttype:LEFTRIGHT}, +{input:"(:", tag:"mo", output:"\u2329", tex:"langle", ttype:LEFTBRACKET}, +{input:":)", tag:"mo", output:"\u232A", tex:"rangle", ttype:RIGHTBRACKET}, +{input:"<<", tag:"mo", output:"\u2329", tex:null, ttype:LEFTBRACKET}, +{input:">>", tag:"mo", output:"\u232A", tex:null, ttype:RIGHTBRACKET}, +{input:"{:", tag:"mo", output:"{:", tex:null, ttype:LEFTBRACKET, invisible:true}, +{input:":}", tag:"mo", output:":}", tex:null, ttype:RIGHTBRACKET, invisible:true}, + +//miscellaneous symbols +{input:"int", tag:"mo", output:"\u222B", tex:null, ttype:CONST}, +{input:"dx", tag:"mi", output:"{:d x:}", tex:null, ttype:DEFINITION}, +{input:"dy", tag:"mi", output:"{:d y:}", tex:null, ttype:DEFINITION}, +{input:"dz", tag:"mi", output:"{:d z:}", tex:null, ttype:DEFINITION}, +{input:"dt", tag:"mi", output:"{:d t:}", tex:null, ttype:DEFINITION}, +{input:"oint", tag:"mo", output:"\u222E", tex:null, ttype:CONST}, +{input:"del", tag:"mo", output:"\u2202", tex:"partial", ttype:CONST}, +{input:"grad", tag:"mo", output:"\u2207", tex:"nabla", ttype:CONST}, +{input:"+-", tag:"mo", output:"\u00B1", tex:"pm", ttype:CONST}, +{input:"O/", tag:"mo", output:"\u2205", tex:"emptyset", ttype:CONST}, +{input:"oo", tag:"mo", output:"\u221E", tex:"infty", ttype:CONST}, +{input:"aleph", tag:"mo", output:"\u2135", tex:null, ttype:CONST}, +{input:"...", tag:"mo", output:"...", tex:"ldots", ttype:CONST}, +{input:":.", tag:"mo", output:"\u2234", tex:"therefore", ttype:CONST}, +{input:"/_", tag:"mo", output:"\u2220", tex:"angle", ttype:CONST}, +{input:"\\ ", tag:"mo", output:"\u00A0", tex:null, ttype:CONST}, +{input:"quad", tag:"mo", output:"\u00A0\u00A0", tex:null, ttype:CONST}, +{input:"qquad", tag:"mo", output:"\u00A0\u00A0\u00A0\u00A0", tex:null, ttype:CONST}, +{input:"cdots", tag:"mo", output:"\u22EF", tex:null, ttype:CONST}, +{input:"vdots", tag:"mo", output:"\u22EE", tex:null, ttype:CONST}, +{input:"ddots", tag:"mo", output:"\u22F1", tex:null, ttype:CONST}, +{input:"diamond", tag:"mo", output:"\u22C4", tex:null, ttype:CONST}, +{input:"square", tag:"mo", output:"\u25A1", tex:null, ttype:CONST}, +{input:"|__", tag:"mo", output:"\u230A", tex:"lfloor", ttype:CONST}, +{input:"__|", tag:"mo", output:"\u230B", tex:"rfloor", ttype:CONST}, +{input:"|~", tag:"mo", output:"\u2308", tex:"lceiling", ttype:CONST}, +{input:"~|", tag:"mo", output:"\u2309", tex:"rceiling", ttype:CONST}, +{input:"CC", tag:"mo", output:"\u2102", tex:null, ttype:CONST}, +{input:"NN", tag:"mo", output:"\u2115", tex:null, ttype:CONST}, +{input:"QQ", tag:"mo", output:"\u211A", tex:null, ttype:CONST}, +{input:"RR", tag:"mo", output:"\u211D", tex:null, ttype:CONST}, +{input:"ZZ", tag:"mo", output:"\u2124", tex:null, ttype:CONST}, +{input:"f", tag:"mi", output:"f", tex:null, ttype:UNARY, func:true}, +{input:"g", tag:"mi", output:"g", tex:null, ttype:UNARY, func:true}, + +//standard functions +{input:"lim", tag:"mo", output:"lim", tex:null, ttype:UNDEROVER}, +{input:"Lim", tag:"mo", output:"Lim", tex:null, ttype:UNDEROVER}, +{input:"sin", tag:"mo", output:"sin", tex:null, ttype:UNARY, func:true}, +{input:"cos", tag:"mo", output:"cos", tex:null, ttype:UNARY, func:true}, +{input:"tan", tag:"mo", output:"tan", tex:null, ttype:UNARY, func:true}, +{input:"sinh", tag:"mo", output:"sinh", tex:null, ttype:UNARY, func:true}, +{input:"cosh", tag:"mo", output:"cosh", tex:null, ttype:UNARY, func:true}, +{input:"tanh", tag:"mo", output:"tanh", tex:null, ttype:UNARY, func:true}, +{input:"cot", tag:"mo", output:"cot", tex:null, ttype:UNARY, func:true}, +{input:"sec", tag:"mo", output:"sec", tex:null, ttype:UNARY, func:true}, +{input:"csc", tag:"mo", output:"csc", tex:null, ttype:UNARY, func:true}, +{input:"log", tag:"mo", output:"log", tex:null, ttype:UNARY, func:true}, +{input:"ln", tag:"mo", output:"ln", tex:null, ttype:UNARY, func:true}, +{input:"det", tag:"mo", output:"det", tex:null, ttype:UNARY, func:true}, +{input:"dim", tag:"mo", output:"dim", tex:null, ttype:CONST}, +{input:"mod", tag:"mo", output:"mod", tex:null, ttype:CONST}, +{input:"gcd", tag:"mo", output:"gcd", tex:null, ttype:UNARY, func:true}, +{input:"lcm", tag:"mo", output:"lcm", tex:null, ttype:UNARY, func:true}, +{input:"lub", tag:"mo", output:"lub", tex:null, ttype:CONST}, +{input:"glb", tag:"mo", output:"glb", tex:null, ttype:CONST}, +{input:"min", tag:"mo", output:"min", tex:null, ttype:UNDEROVER}, +{input:"max", tag:"mo", output:"max", tex:null, ttype:UNDEROVER}, + +//arrows +{input:"uarr", tag:"mo", output:"\u2191", tex:"uparrow", ttype:CONST}, +{input:"darr", tag:"mo", output:"\u2193", tex:"downarrow", ttype:CONST}, +{input:"rarr", tag:"mo", output:"\u2192", tex:"rightarrow", ttype:CONST}, +{input:"->", tag:"mo", output:"\u2192", tex:"to", ttype:CONST}, +{input:"|->", tag:"mo", output:"\u21A6", tex:"mapsto", ttype:CONST}, +{input:"larr", tag:"mo", output:"\u2190", tex:"leftarrow", ttype:CONST}, +{input:"harr", tag:"mo", output:"\u2194", tex:"leftrightarrow", ttype:CONST}, +{input:"rArr", tag:"mo", output:"\u21D2", tex:"Rightarrow", ttype:CONST}, +{input:"lArr", tag:"mo", output:"\u21D0", tex:"Leftarrow", ttype:CONST}, +{input:"hArr", tag:"mo", output:"\u21D4", tex:"Leftrightarrow", ttype:CONST}, + +//commands with argument +AMsqrt, AMroot, AMfrac, AMdiv, AMover, AMsub, AMsup, +{input:"hat", tag:"mover", output:"\u005E", tex:null, ttype:UNARY, acc:true}, +{input:"bar", tag:"mover", output:"\u00AF", tex:"overline", ttype:UNARY, acc:true}, +{input:"vec", tag:"mover", output:"\u2192", tex:null, ttype:UNARY, acc:true}, +{input:"dot", tag:"mover", output:".", tex:null, ttype:UNARY, acc:true}, +{input:"ddot", tag:"mover", output:"..", tex:null, ttype:UNARY, acc:true}, +{input:"ul", tag:"munder", output:"\u0332", tex:"underline", ttype:UNARY, acc:true}, +AMtext, AMmbox, AMquote, +{input:"bb", tag:"mstyle", atname:"fontweight", atval:"bold", output:"bb", tex:null, ttype:UNARY}, +{input:"mathbf", tag:"mstyle", atname:"fontweight", atval:"bold", output:"mathbf", tex:null, ttype:UNARY}, +{input:"sf", tag:"mstyle", atname:"fontfamily", atval:"sans-serif", output:"sf", tex:null, ttype:UNARY}, +{input:"mathsf", tag:"mstyle", atname:"fontfamily", atval:"sans-serif", output:"mathsf", tex:null, ttype:UNARY}, +{input:"bbb", tag:"mstyle", atname:"mathvariant", atval:"double-struck", output:"bbb", tex:null, ttype:UNARY, codes:AMbbb}, +{input:"mathbb", tag:"mstyle", atname:"mathvariant", atval:"double-struck", output:"mathbb", tex:null, ttype:UNARY, codes:AMbbb}, +{input:"cc", tag:"mstyle", atname:"mathvariant", atval:"script", output:"cc", tex:null, ttype:UNARY, codes:AMcal}, +{input:"mathcal", tag:"mstyle", atname:"mathvariant", atval:"script", output:"mathcal", tex:null, ttype:UNARY, codes:AMcal}, +{input:"tt", tag:"mstyle", atname:"fontfamily", atval:"monospace", output:"tt", tex:null, ttype:UNARY}, +{input:"mathtt", tag:"mstyle", atname:"fontfamily", atval:"monospace", output:"mathtt", tex:null, ttype:UNARY}, +{input:"fr", tag:"mstyle", atname:"mathvariant", atval:"fraktur", output:"fr", tex:null, ttype:UNARY, codes:AMfrk}, +{input:"mathfrak", tag:"mstyle", atname:"mathvariant", atval:"fraktur", output:"mathfrak", tex:null, ttype:UNARY, codes:AMfrk} +]; + +function compareNames(s1,s2) { + if (s1.input > s2.input) return 1 + else return -1; +} + +var AMnames = []; //list of input symbols + +function AMinitSymbols() { + var texsymbols = [], i; + for (i=0; i=n where str appears or would be inserted +// assumes arr is sorted + if (n==0) { + var h,m; + n = -1; + h = arr.length; + while (n+1> 1; + if (arr[m]=str +} + +function AMgetSymbol(str) { +//return maximal initial substring of str that appears in names +//return null if there is none + var k = 0; //new pos + var j = 0; //old pos + var mk; //match pos + var st; + var tagst; + var match = ""; + var more = true; + for (var i=1; i<=str.length && more; i++) { + st = str.slice(0,i); //initial substring of length i + j = k; + k = AMposition(AMnames, st, j); + if (k=AMnames[k]; + } + AMpreviousSymbol=AMcurrentSymbol; + if (match!=""){ + AMcurrentSymbol=AMsymbols[mk].ttype; + return AMsymbols[mk]; + } +// if str[0] is a digit or - return maxsubstring of digits.digits + AMcurrentSymbol=CONST; + k = 1; + st = str.slice(0,1); + var integ = true; + while ("0"<=st && st<="9" && k<=str.length) { + st = str.slice(k,k+1); + k++; + } + if (st == decimalsign) { + st = str.slice(k,k+1); + if ("0"<=st && st<="9") { + integ = false; + k++; + while ("0"<=st && st<="9" && k<=str.length) { + st = str.slice(k,k+1); + k++; + } + } + } + if ((integ && k>1) || k>2) { + st = str.slice(0,k-1); + tagst = "mn"; + } else { + k = 2; + st = str.slice(0,1); //take 1 character + tagst = (("A">st || st>"Z") && ("a">st || st>"z")?"mo":"mi"); + } + if (st=="-" && AMpreviousSymbol==INFIX) { + AMcurrentSymbol = INFIX; //trick "/" into recognizing "-" on second parse + return {input:st, tag:tagst, output:st, ttype:UNARY, func:true}; + } + return {input:st, tag:tagst, output:st, ttype:CONST}; +} + +function AMremoveBrackets(node) { + var st; + if (node.nodeName=="mrow") { + st = node.firstChild.firstChild.nodeValue; + if (st=="(" || st=="[" || st=="{") node.removeChild(node.firstChild); + } + if (node.nodeName=="mrow") { + st = node.lastChild.firstChild.nodeValue; + if (st==")" || st=="]" || st=="}") node.removeChild(node.lastChild); + } +} + +/*Parsing ASCII math expressions with the following grammar +v ::= [A-Za-z] | greek letters | numbers | other constant symbols +u ::= sqrt | text | bb | other unary symbols for font commands +b ::= frac | root | stackrel binary symbols +l ::= ( | [ | { | (: | {: left brackets +r ::= ) | ] | } | :) | :} right brackets +S ::= v | lEr | uS | bSS Simple expression +I ::= S_S | S^S | S_S^S | S Intermediate expression +E ::= IE | I/I Expression +Each terminal symbol is translated into a corresponding mathml node.*/ + +var AMnestingDepth,AMpreviousSymbol,AMcurrentSymbol; + +function AMparseSexpr(str) { //parses str and returns [node,tailstr] + var symbol, node, result, i, st,// rightvert = false, + newFrag = document.createDocumentFragment(); + str = AMremoveCharsAndBlanks(str,0); + symbol = AMgetSymbol(str); //either a token or a bracket or empty + if (symbol == null || symbol.ttype == RIGHTBRACKET && AMnestingDepth > 0) { + return [null,str]; + } + if (symbol.ttype == DEFINITION) { + str = symbol.output+AMremoveCharsAndBlanks(str,symbol.input.length); + symbol = AMgetSymbol(str); + } + switch (symbol.ttype) { + case UNDEROVER: + case CONST: + str = AMremoveCharsAndBlanks(str,symbol.input.length); + return [AMcreateMmlNode(symbol.tag, //its a constant + document.createTextNode(symbol.output)),str]; + case LEFTBRACKET: //read (expr+) + AMnestingDepth++; + str = AMremoveCharsAndBlanks(str,symbol.input.length); + result = AMparseExpr(str,true); + AMnestingDepth--; + if (typeof symbol.invisible == "boolean" && symbol.invisible) + node = AMcreateMmlNode("mrow",result[0]); + else { + node = AMcreateMmlNode("mo",document.createTextNode(symbol.output)); + node = AMcreateMmlNode("mrow",node); + node.appendChild(result[0]); + } + return [node,result[1]]; + case TEXT: + if (symbol!=AMquote) str = AMremoveCharsAndBlanks(str,symbol.input.length); + if (str.charAt(0)=="{") i=str.indexOf("}"); + else if (str.charAt(0)=="(") i=str.indexOf(")"); + else if (str.charAt(0)=="[") i=str.indexOf("]"); + else if (symbol==AMquote) i=str.slice(1).indexOf("\"")+1; + else i = 0; + if (i==-1) i = str.length; + st = str.slice(1,i); + if (st.charAt(0) == " ") { + node = AMcreateElementMathML("mspace"); + node.setAttribute("width","1ex"); + newFrag.appendChild(node); + } + newFrag.appendChild( + AMcreateMmlNode(symbol.tag,document.createTextNode(st))); + if (st.charAt(st.length-1) == " ") { + node = AMcreateElementMathML("mspace"); + node.setAttribute("width","1ex"); + newFrag.appendChild(node); + } + str = AMremoveCharsAndBlanks(str,i+1); + return [AMcreateMmlNode("mrow",newFrag),str]; + case UNARY: + str = AMremoveCharsAndBlanks(str,symbol.input.length); + result = AMparseSexpr(str); + if (result[0]==null) return [AMcreateMmlNode(symbol.tag, + document.createTextNode(symbol.output)),str]; + if (typeof symbol.func == "boolean" && symbol.func) { // functions hack + st = str.charAt(0); + if (st=="^" || st=="_" || st=="/" || st=="|" || st==",") { + return [AMcreateMmlNode(symbol.tag, + document.createTextNode(symbol.output)),str]; + } else { + node = AMcreateMmlNode("mrow", + AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output))); + node.appendChild(result[0]); + return [node,result[1]]; + } + } + AMremoveBrackets(result[0]); + if (symbol.input == "sqrt") { // sqrt + return [AMcreateMmlNode(symbol.tag,result[0]),result[1]]; + } else if (typeof symbol.acc == "boolean" && symbol.acc) { // accent + node = AMcreateMmlNode(symbol.tag,result[0]); + node.appendChild(AMcreateMmlNode("mo",document.createTextNode(symbol.output))); + return [node,result[1]]; + } else { // font change command + if (!isIE && typeof symbol.codes != "undefined") { + for (i=0; i64 && st.charCodeAt(j)<91) newst = newst + + String.fromCharCode(symbol.codes[st.charCodeAt(j)-65]); + else newst = newst + st.charAt(j); + if (result[0].nodeName=="mi") + result[0]=AMcreateElementMathML("mo"). + appendChild(document.createTextNode(newst)); + else result[0].replaceChild(AMcreateElementMathML("mo"). + appendChild(document.createTextNode(newst)),result[0].childNodes[i]); + } + } + node = AMcreateMmlNode(symbol.tag,result[0]); + node.setAttribute(symbol.atname,symbol.atval); + return [node,result[1]]; + } + case BINARY: + str = AMremoveCharsAndBlanks(str,symbol.input.length); + result = AMparseSexpr(str); + if (result[0]==null) return [AMcreateMmlNode("mo", + document.createTextNode(symbol.input)),str]; + AMremoveBrackets(result[0]); + var result2 = AMparseSexpr(result[1]); + if (result2[0]==null) return [AMcreateMmlNode("mo", + document.createTextNode(symbol.input)),str]; + AMremoveBrackets(result2[0]); + if (symbol.input=="root" || symbol.input=="stackrel") + newFrag.appendChild(result2[0]); + newFrag.appendChild(result[0]); + if (symbol.input=="frac") newFrag.appendChild(result2[0]); + return [AMcreateMmlNode(symbol.tag,newFrag),result2[1]]; + case INFIX: + str = AMremoveCharsAndBlanks(str,symbol.input.length); + return [AMcreateMmlNode("mo",document.createTextNode(symbol.output)),str]; + case SPACE: + str = AMremoveCharsAndBlanks(str,symbol.input.length); + node = AMcreateElementMathML("mspace"); + node.setAttribute("width","1ex"); + newFrag.appendChild(node); + newFrag.appendChild( + AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output))); + node = AMcreateElementMathML("mspace"); + node.setAttribute("width","1ex"); + newFrag.appendChild(node); + return [AMcreateMmlNode("mrow",newFrag),str]; + case LEFTRIGHT: +// if (rightvert) return [null,str]; else rightvert = true; + AMnestingDepth++; + str = AMremoveCharsAndBlanks(str,symbol.input.length); + result = AMparseExpr(str,false); + AMnestingDepth--; + var st = ""; + if (result[0].lastChild!=null) + st = result[0].lastChild.firstChild.nodeValue; + if (st == "|") { // its an absolute value subterm + node = AMcreateMmlNode("mo",document.createTextNode(symbol.output)); + node = AMcreateMmlNode("mrow",node); + node.appendChild(result[0]); + return [node,result[1]]; + } else { // the "|" is a \mid + node = AMcreateMmlNode("mo",document.createTextNode(symbol.output)); + node = AMcreateMmlNode("mrow",node); + return [node,str]; + } + default: +//alert("default"); + str = AMremoveCharsAndBlanks(str,symbol.input.length); + return [AMcreateMmlNode(symbol.tag, //its a constant + document.createTextNode(symbol.output)),str]; + } +} + +function AMparseIexpr(str) { + var symbol, sym1, sym2, node, result, underover; + str = AMremoveCharsAndBlanks(str,0); + sym1 = AMgetSymbol(str); + result = AMparseSexpr(str); + node = result[0]; + str = result[1]; + symbol = AMgetSymbol(str); + if (symbol.ttype == INFIX && symbol.input != "/") { + str = AMremoveCharsAndBlanks(str,symbol.input.length); +// if (symbol.input == "/") result = AMparseIexpr(str); else ... + result = AMparseSexpr(str); + if (result[0] == null) // show box in place of missing argument + result[0] = AMcreateMmlNode("mo",document.createTextNode("\u25A1")); + else AMremoveBrackets(result[0]); + str = result[1]; +// if (symbol.input == "/") AMremoveBrackets(node); + if (symbol.input == "_") { + sym2 = AMgetSymbol(str); + underover = (sym1.ttype == UNDEROVER); + if (sym2.input == "^") { + str = AMremoveCharsAndBlanks(str,sym2.input.length); + var res2 = AMparseSexpr(str); + AMremoveBrackets(res2[0]); + str = res2[1]; + node = AMcreateMmlNode((underover?"munderover":"msubsup"),node); + node.appendChild(result[0]); + node.appendChild(res2[0]); + node = AMcreateMmlNode("mrow",node); // so sum does not stretch + } else { + node = AMcreateMmlNode((underover?"munder":"msub"),node); + node.appendChild(result[0]); + } + } else { + node = AMcreateMmlNode(symbol.tag,node); + node.appendChild(result[0]); + } + } + return [node,str]; +} + +function AMparseExpr(str,rightbracket) { + var symbol, node, result, i, nodeList = [], + newFrag = document.createDocumentFragment(); + do { + str = AMremoveCharsAndBlanks(str,0); + result = AMparseIexpr(str); + node = result[0]; + str = result[1]; + symbol = AMgetSymbol(str); + if (symbol.ttype == INFIX && symbol.input == "/") { + str = AMremoveCharsAndBlanks(str,symbol.input.length); + result = AMparseIexpr(str); + if (result[0] == null) // show box in place of missing argument + result[0] = AMcreateMmlNode("mo",document.createTextNode("\u25A1")); + else AMremoveBrackets(result[0]); + str = result[1]; + AMremoveBrackets(node); + node = AMcreateMmlNode(symbol.tag,node); + node.appendChild(result[0]); + newFrag.appendChild(node); + symbol = AMgetSymbol(str); + } + else if (node!=undefined) newFrag.appendChild(node); + } while ((symbol.ttype != RIGHTBRACKET && + (symbol.ttype != LEFTRIGHT || rightbracket) + || AMnestingDepth == 0) && symbol!=null && symbol.output!=""); + if (symbol.ttype == RIGHTBRACKET || symbol.ttype == LEFTRIGHT) { +// if (AMnestingDepth > 0) AMnestingDepth--; + var len = newFrag.childNodes.length; + if (len>0 && newFrag.childNodes[len-1].nodeName == "mrow" && len>1 && + newFrag.childNodes[len-2].nodeName == "mo" && + newFrag.childNodes[len-2].firstChild.nodeValue == ",") { //matrix + var right = newFrag.childNodes[len-1].lastChild.firstChild.nodeValue; + if (right==")" || right=="]") { + var left = newFrag.childNodes[len-1].firstChild.firstChild.nodeValue; + if (left=="(" && right==")" && symbol.output != "}" || + left=="[" && right=="]") { + var pos = []; // positions of commas + var matrix = true; + var m = newFrag.childNodes.length; + for (i=0; matrix && i1) matrix = pos[i].length == pos[i-2].length; + } + if (matrix) { + var row, frag, n, k, table = document.createDocumentFragment(); + for (i=0; i(-,-,...,-,-) + n = node.childNodes.length; + k = 0; + node.removeChild(node.firstChild); //remove ( + for (j=1; j2) { + newFrag.removeChild(newFrag.firstChild); //remove ) + newFrag.removeChild(newFrag.firstChild); //remove , + } + table.appendChild(AMcreateMmlNode("mtr",row)); + } + node = AMcreateMmlNode("mtable",table); + if (typeof symbol.invisible == "boolean" && symbol.invisible) node.setAttribute("columnalign","left"); + newFrag.replaceChild(node,newFrag.firstChild); + } + } + } + } + str = AMremoveCharsAndBlanks(str,symbol.input.length); + if (typeof symbol.invisible != "boolean" || !symbol.invisible) { + node = AMcreateMmlNode("mo",document.createTextNode(symbol.output)); + newFrag.appendChild(node); + } + } + return [newFrag,str]; +} + +function AMparseMath(str) { + var result, node = AMcreateElementMathML("mstyle"); + if (mathcolor != "") node.setAttribute("mathcolor",mathcolor); + if (displaystyle) node.setAttribute("displaystyle","true"); + if (mathfontfamily != "") node.setAttribute("fontfamily",mathfontfamily); + AMnestingDepth = 0; + node.appendChild(AMparseExpr(str.replace(/^\s+/g,""),false)[0]); + node = AMcreateMmlNode("math",node); + if (showasciiformulaonhover) //fixed by djhsu so newline + node.setAttribute("title",str.replace(/\s+/g," "));//does not show in Gecko + if (mathfontfamily != "" && (isIE || mathfontfamily != "serif")) { + var fnode = AMcreateElementXHTML("font"); + fnode.setAttribute("face",mathfontfamily); + fnode.appendChild(node); + return fnode; + } + return node; +} + +function AMstrarr2docFrag(arr, linebreaks) { + var newFrag=document.createDocumentFragment(); + var expr = false; + for (var i=0; i1 || mtch) { + if (checkForMathML) { + checkForMathML = false; + var nd = AMisMathMLavailable(); + AMnoMathML = nd != null; + if (AMnoMathML && notifyIfNoMathML) + if (alertIfNoMathML) + alert("To view the ASCIIMathML notation use Internet Explorer 6 +\nMathPlayer (free from www.dessci.com)\n\ + or Firefox/Mozilla/Netscape"); + else AMbody.insertBefore(nd,AMbody.childNodes[0]); + } + if (!AMnoMathML) { + frg = AMstrarr2docFrag(arr,n.nodeType==8); + var len = frg.childNodes.length; + n.parentNode.replaceChild(frg,n); + return len-1; + } else return 0; + } + } + } else return 0; + } else if (n.nodeName!="math") { + for (i=0; i"); + document.write(""); +} + +// GO1.1 Generic onload by Brothercake +// http://www.brothercake.com/ +//onload function (replaces the onload="translate()" in the tag) +function generic() +{ + translate(); +}; +//setup onload function +if(typeof window.addEventListener != 'undefined') +{ + //.. gecko, safari, konqueror and standard + window.addEventListener('load', generic, false); +} +else if(typeof document.addEventListener != 'undefined') +{ + //.. opera 7 + document.addEventListener('load', generic, false); +} +else if(typeof window.attachEvent != 'undefined') +{ + //.. win/ie + window.attachEvent('onload', generic); +} +//** remove this condition to degrade older browsers +else +{ + //.. mac/ie5 and anything else that gets this far + //if there's an existing onload function + if(typeof window.onload == 'function') + { + //store it + var existing = onload; + //add new onload handler + window.onload = function() + { + //call existing onload function + existing(); + //call generic onload function + generic(); + }; + } + else + { + //setup onload function + window.onload = generic; + } +} diff --git a/stylesheets/javascripts/LaTeXMathML.js b/stylesheets/javascripts/LaTeXMathML.js new file mode 100644 index 0000000..51dba70 --- /dev/null +++ b/stylesheets/javascripts/LaTeXMathML.js @@ -0,0 +1,1223 @@ +/* +LaTeXMathML.js +============== + +This file, in this form, is due to Douglas Woodall, June 2006. +It contains JavaScript functions to convert (most simple) LaTeX +math notation to Presentation MathML. It was obtained by +downloading the file ASCIIMathML.js from + http://www1.chapman.edu/~jipsen/mathml/asciimathdownload/ +and modifying it so that it carries out ONLY those conversions +that would be carried out in LaTeX. A description of the original +file, with examples, can be found at + www1.chapman.edu/~jipsen/mathml/asciimath.html + ASCIIMathML: Math on the web for everyone + +Here is the header notice from the original file: + +ASCIIMathML.js +============== +This file contains JavaScript functions to convert ASCII math notation +to Presentation MathML. The conversion is done while the (X)HTML page +loads, and should work with Firefox/Mozilla/Netscape 7+ and Internet +Explorer 6+MathPlayer (http://www.dessci.com/en/products/mathplayer/). +Just add the next line to your (X)HTML page with this file in the same folder: +This is a convenient and inexpensive solution for authoring MathML. + +Version 1.4.7 Dec 15, 2005, (c) Peter Jipsen http://www.chapman.edu/~jipsen +Latest version at http://www.chapman.edu/~jipsen/mathml/ASCIIMathML.js +For changes see http://www.chapman.edu/~jipsen/mathml/asciimathchanges.txt +If you use it on a webpage, please send the URL to jipsen@chapman.edu + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License (at http://www.gnu.org/copyleft/gpl.html) +for more details. + +LaTeXMathML.js (ctd) +============== + +The instructions for use are the same as for the original +ASCIIMathML.js, except that of course the line you add to your +file should be +Or use absolute path names if the file is not in the same folder +as your (X)HTML page. +*/ + +var checkForMathML = true; // check if browser can display MathML +var notifyIfNoMathML = true; // display note if no MathML capability +var alertIfNoMathML = false; // show alert box if no MathML capability +// was "red": +var mathcolor = ""; // change it to "" (to inherit) or any other color +// was "serif": +var mathfontfamily = ""; // change to "" to inherit (works in IE) + // or another family (e.g. "arial") +var showasciiformulaonhover = true; // helps students learn ASCIIMath +/* +// Commented out by DRW -- not now used -- see DELIMITERS (twice) near the end +var displaystyle = false; // puts limits above and below large operators +var decimalsign = "."; // change to "," if you like, beware of `(1,2)`! +var AMdelimiter1 = "`", AMescape1 = "\\\\`"; // can use other characters +var AMdelimiter2 = "$", AMescape2 = "\\\\\\$", AMdelimiter2regexp = "\\$"; +var doubleblankmathdelimiter = false; // if true, x+1 is equal to `x+1` + // for IE this works only in +//var separatetokens;// has been removed (email me if this is a problem) +*/ +var isIE = document.createElementNS==null; + +if (document.getElementById==null) + alert("This webpage requires a recent browser such as\ +\nMozilla/Netscape 7+ or Internet Explorer 6+MathPlayer") + +// all further global variables start with "AM" + +function AMcreateElementXHTML(t) { + if (isIE) return document.createElement(t); + else return document.createElementNS("http://www.w3.org/1999/xhtml",t); +} + +function AMnoMathMLNote() { + var nd = AMcreateElementXHTML("h3"); + nd.setAttribute("align","center") + nd.appendChild(AMcreateElementXHTML("p")); + nd.appendChild(document.createTextNode("To view the ")); + var an = AMcreateElementXHTML("a"); + an.appendChild(document.createTextNode("LaTeXMathML")); + an.setAttribute("href","http://www.maths.nott.ac.uk/personal/drw/lm.html"); + nd.appendChild(an); + nd.appendChild(document.createTextNode(" notation use Internet Explorer 6+")); + an = AMcreateElementXHTML("a"); + an.appendChild(document.createTextNode("MathPlayer")); + an.setAttribute("href","http://www.dessci.com/en/products/mathplayer/download.htm"); + nd.appendChild(an); + nd.appendChild(document.createTextNode(" or Netscape/Mozilla/Firefox")); + nd.appendChild(AMcreateElementXHTML("p")); + return nd; +} + +function AMisMathMLavailable() { + if (navigator.appName.slice(0,8)=="Netscape") + if (navigator.appVersion.slice(0,1)>="5") return null; + else return AMnoMathMLNote(); + else if (navigator.appName.slice(0,9)=="Microsoft") + try { + var ActiveX = new ActiveXObject("MathPlayer.Factory.1"); + return null; + } catch (e) { + return AMnoMathMLNote(); + } + else return AMnoMathMLNote(); +} + +// character lists for Mozilla/Netscape fonts +var AMcal = [0xEF35,0x212C,0xEF36,0xEF37,0x2130,0x2131,0xEF38,0x210B,0x2110,0xEF39,0xEF3A,0x2112,0x2133,0xEF3B,0xEF3C,0xEF3D,0xEF3E,0x211B,0xEF3F,0xEF40,0xEF41,0xEF42,0xEF43,0xEF44,0xEF45,0xEF46]; +var AMfrk = [0xEF5D,0xEF5E,0x212D,0xEF5F,0xEF60,0xEF61,0xEF62,0x210C,0x2111,0xEF63,0xEF64,0xEF65,0xEF66,0xEF67,0xEF68,0xEF69,0xEF6A,0x211C,0xEF6B,0xEF6C,0xEF6D,0xEF6E,0xEF6F,0xEF70,0xEF71,0x2128]; +var AMbbb = [0xEF8C,0xEF8D,0x2102,0xEF8E,0xEF8F,0xEF90,0xEF91,0x210D,0xEF92,0xEF93,0xEF94,0xEF95,0xEF96,0x2115,0xEF97,0x2119,0x211A,0x211D,0xEF98,0xEF99,0xEF9A,0xEF9B,0xEF9C,0xEF9D,0xEF9E,0x2124]; + +var CONST = 0, UNARY = 1, BINARY = 2, INFIX = 3, LEFTBRACKET = 4, + RIGHTBRACKET = 5, SPACE = 6, UNDEROVER = 7, DEFINITION = 8, + TEXT = 9, BIG = 10, LONG = 11, STRETCHY = 12, MATRIX = 13; // token types + +var AMsqrt = {input:"\\sqrt", tag:"msqrt", output:"sqrt", ttype:UNARY}, + AMroot = {input:"\\root", tag:"mroot", output:"root", ttype:BINARY}, + AMfrac = {input:"\\frac", tag:"mfrac", output:"/", ttype:BINARY}, + AMover = {input:"\\stackrel", tag:"mover", output:"stackrel", ttype:BINARY}, + AMatop = {input:"\\atop", tag:"mfrac", output:"", ttype:INFIX}, + AMchoose = {input:"\\choose", tag:"mfrac", output:"", ttype:INFIX}, + AMsub = {input:"_", tag:"msub", output:"_", ttype:INFIX}, + AMsup = {input:"^", tag:"msup", output:"^", ttype:INFIX}, + AMtext = {input:"\\mathrm", tag:"mtext", output:"text", ttype:TEXT}, + AMmbox = {input:"\\mbox", tag:"mtext", output:"mbox", ttype:TEXT}; + +// Commented out by DRW to prevent 1/2 turning into a 2-line fraction +// AMdiv = {input:"/", tag:"mfrac", output:"/", ttype:INFIX}, +// Commented out by DRW so that " prints literally in equations +// AMquote = {input:"\"", tag:"mtext", output:"mbox", ttype:TEXT}; + +var AMsymbols = [ +//Greek letters +{input:"\\alpha", tag:"mi", output:"\u03B1", ttype:CONST}, +{input:"\\beta", tag:"mi", output:"\u03B2", ttype:CONST}, +{input:"\\gamma", tag:"mi", output:"\u03B3", ttype:CONST}, +{input:"\\delta", tag:"mi", output:"\u03B4", ttype:CONST}, +{input:"\\epsilon", tag:"mi", output:"\u03B5", ttype:CONST}, +{input:"\\varepsilon", tag:"mi", output:"\u025B", ttype:CONST}, +{input:"\\zeta", tag:"mi", output:"\u03B6", ttype:CONST}, +{input:"\\eta", tag:"mi", output:"\u03B7", ttype:CONST}, +{input:"\\theta", tag:"mi", output:"\u03B8", ttype:CONST}, +{input:"\\vartheta", tag:"mi", output:"\u03D1", ttype:CONST}, +{input:"\\iota", tag:"mi", output:"\u03B9", ttype:CONST}, +{input:"\\kappa", tag:"mi", output:"\u03BA", ttype:CONST}, +{input:"\\lambda", tag:"mi", output:"\u03BB", ttype:CONST}, +{input:"\\mu", tag:"mi", output:"\u03BC", ttype:CONST}, +{input:"\\nu", tag:"mi", output:"\u03BD", ttype:CONST}, +{input:"\\xi", tag:"mi", output:"\u03BE", ttype:CONST}, +{input:"\\pi", tag:"mi", output:"\u03C0", ttype:CONST}, +{input:"\\varpi", tag:"mi", output:"\u03D6", ttype:CONST}, +{input:"\\rho", tag:"mi", output:"\u03C1", ttype:CONST}, +{input:"\\varrho", tag:"mi", output:"\u03F1", ttype:CONST}, +{input:"\\varsigma", tag:"mi", output:"\u03C2", ttype:CONST}, +{input:"\\sigma", tag:"mi", output:"\u03C3", ttype:CONST}, +{input:"\\tau", tag:"mi", output:"\u03C4", ttype:CONST}, +{input:"\\upsilon", tag:"mi", output:"\u03C5", ttype:CONST}, +{input:"\\phi", tag:"mi", output:"\u03C6", ttype:CONST}, +{input:"\\varphi", tag:"mi", output:"\u03D5", ttype:CONST}, +{input:"\\chi", tag:"mi", output:"\u03C7", ttype:CONST}, +{input:"\\psi", tag:"mi", output:"\u03C8", ttype:CONST}, +{input:"\\omega", tag:"mi", output:"\u03C9", ttype:CONST}, +{input:"\\Gamma", tag:"mo", output:"\u0393", ttype:CONST}, +{input:"\\Delta", tag:"mo", output:"\u0394", ttype:CONST}, +{input:"\\Theta", tag:"mo", output:"\u0398", ttype:CONST}, +{input:"\\Lambda", tag:"mo", output:"\u039B", ttype:CONST}, +{input:"\\Xi", tag:"mo", output:"\u039E", ttype:CONST}, +{input:"\\Pi", tag:"mo", output:"\u03A0", ttype:CONST}, +{input:"\\Sigma", tag:"mo", output:"\u03A3", ttype:CONST}, +{input:"\\Upsilon", tag:"mo", output:"\u03A5", ttype:CONST}, +{input:"\\Phi", tag:"mo", output:"\u03A6", ttype:CONST}, +{input:"\\Psi", tag:"mo", output:"\u03A8", ttype:CONST}, +{input:"\\Omega", tag:"mo", output:"\u03A9", ttype:CONST}, + +//fractions +{input:"\\frac12", tag:"mo", output:"\u00BD", ttype:CONST}, +{input:"\\frac14", tag:"mo", output:"\u00BC", ttype:CONST}, +{input:"\\frac34", tag:"mo", output:"\u00BE", ttype:CONST}, +{input:"\\frac13", tag:"mo", output:"\u2153", ttype:CONST}, +{input:"\\frac23", tag:"mo", output:"\u2154", ttype:CONST}, +{input:"\\frac15", tag:"mo", output:"\u2155", ttype:CONST}, +{input:"\\frac25", tag:"mo", output:"\u2156", ttype:CONST}, +{input:"\\frac35", tag:"mo", output:"\u2157", ttype:CONST}, +{input:"\\frac45", tag:"mo", output:"\u2158", ttype:CONST}, +{input:"\\frac16", tag:"mo", output:"\u2159", ttype:CONST}, +{input:"\\frac56", tag:"mo", output:"\u215A", ttype:CONST}, +{input:"\\frac18", tag:"mo", output:"\u215B", ttype:CONST}, +{input:"\\frac38", tag:"mo", output:"\u215C", ttype:CONST}, +{input:"\\frac58", tag:"mo", output:"\u215D", ttype:CONST}, +{input:"\\frac78", tag:"mo", output:"\u215E", ttype:CONST}, + +//binary operation symbols +{input:"\\pm", tag:"mo", output:"\u00B1", ttype:CONST}, +{input:"\\mp", tag:"mo", output:"\u2213", ttype:CONST}, +{input:"\\triangleleft",tag:"mo", output:"\u22B2", ttype:CONST}, +{input:"\\triangleright",tag:"mo",output:"\u22B3", ttype:CONST}, +{input:"\\cdot", tag:"mo", output:"\u22C5", ttype:CONST}, +{input:"\\star", tag:"mo", output:"\u22C6", ttype:CONST}, +{input:"\\ast", tag:"mo", output:"\u002A", ttype:CONST}, +{input:"\\times", tag:"mo", output:"\u00D7", ttype:CONST}, +{input:"\\div", tag:"mo", output:"\u00F7", ttype:CONST}, +{input:"\\circ", tag:"mo", output:"\u2218", ttype:CONST}, +//{input:"\\bullet", tag:"mo", output:"\u2219", ttype:CONST}, +{input:"\\bullet", tag:"mo", output:"\u2022", ttype:CONST}, +{input:"\\oplus", tag:"mo", output:"\u2295", ttype:CONST}, +{input:"\\ominus", tag:"mo", output:"\u2296", ttype:CONST}, +{input:"\\otimes", tag:"mo", output:"\u2297", ttype:CONST}, +{input:"\\bigcirc", tag:"mo", output:"\u25CB", ttype:CONST}, +{input:"\\oslash", tag:"mo", output:"\u2298", ttype:CONST}, +{input:"\\odot", tag:"mo", output:"\u2299", ttype:CONST}, +{input:"\\land", tag:"mo", output:"\u2227", ttype:CONST}, +{input:"\\wedge", tag:"mo", output:"\u2227", ttype:CONST}, +{input:"\\lor", tag:"mo", output:"\u2228", ttype:CONST}, +{input:"\\vee", tag:"mo", output:"\u2228", ttype:CONST}, +{input:"\\cap", tag:"mo", output:"\u2229", ttype:CONST}, +{input:"\\cup", tag:"mo", output:"\u222A", ttype:CONST}, +{input:"\\sqcap", tag:"mo", output:"\u2293", ttype:CONST}, +{input:"\\sqcup", tag:"mo", output:"\u2294", ttype:CONST}, +{input:"\\uplus", tag:"mo", output:"\u228E", ttype:CONST}, +{input:"\\amalg", tag:"mo", output:"\u2210", ttype:CONST}, +{input:"\\bigtriangleup",tag:"mo",output:"\u25B3", ttype:CONST}, +{input:"\\bigtriangledown",tag:"mo",output:"\u25BD", ttype:CONST}, +{input:"\\dag", tag:"mo", output:"\u2020", ttype:CONST}, +{input:"\\dagger", tag:"mo", output:"\u2020", ttype:CONST}, +{input:"\\ddag", tag:"mo", output:"\u2021", ttype:CONST}, +{input:"\\ddagger", tag:"mo", output:"\u2021", ttype:CONST}, +{input:"\\lhd", tag:"mo", output:"\u22B2", ttype:CONST}, +{input:"\\rhd", tag:"mo", output:"\u22B3", ttype:CONST}, +{input:"\\unlhd", tag:"mo", output:"\u22B4", ttype:CONST}, +{input:"\\unrhd", tag:"mo", output:"\u22B5", ttype:CONST}, + + +//BIG Operators +{input:"\\sum", tag:"mo", output:"\u2211", ttype:UNDEROVER}, +{input:"\\prod", tag:"mo", output:"\u220F", ttype:UNDEROVER}, +{input:"\\bigcap", tag:"mo", output:"\u22C2", ttype:UNDEROVER}, +{input:"\\bigcup", tag:"mo", output:"\u22C3", ttype:UNDEROVER}, +{input:"\\bigwedge", tag:"mo", output:"\u22C0", ttype:UNDEROVER}, +{input:"\\bigvee", tag:"mo", output:"\u22C1", ttype:UNDEROVER}, +{input:"\\bigsqcap", tag:"mo", output:"\u2A05", ttype:UNDEROVER}, +{input:"\\bigsqcup", tag:"mo", output:"\u2A06", ttype:UNDEROVER}, +{input:"\\coprod", tag:"mo", output:"\u2210", ttype:UNDEROVER}, +{input:"\\bigoplus", tag:"mo", output:"\u2A01", ttype:UNDEROVER}, +{input:"\\bigotimes", tag:"mo", output:"\u2A02", ttype:UNDEROVER}, +{input:"\\bigodot", tag:"mo", output:"\u2A00", ttype:UNDEROVER}, +{input:"\\biguplus", tag:"mo", output:"\u2A04", ttype:UNDEROVER}, +{input:"\\int", tag:"mo", output:"\u222B", ttype:CONST}, +{input:"\\oint", tag:"mo", output:"\u222E", ttype:CONST}, + +//binary relation symbols +{input:":=", tag:"mo", output:":=", ttype:CONST}, +{input:"\\lt", tag:"mo", output:"<", ttype:CONST}, +{input:"\\gt", tag:"mo", output:">", ttype:CONST}, +{input:"\\ne", tag:"mo", output:"\u2260", ttype:CONST}, +{input:"\\neq", tag:"mo", output:"\u2260", ttype:CONST}, +{input:"\\le", tag:"mo", output:"\u2264", ttype:CONST}, +{input:"\\leq", tag:"mo", output:"\u2264", ttype:CONST}, +{input:"\\leqslant", tag:"mo", output:"\u2264", ttype:CONST}, +{input:"\\ge", tag:"mo", output:"\u2265", ttype:CONST}, +{input:"\\geq", tag:"mo", output:"\u2265", ttype:CONST}, +{input:"\\geqslant", tag:"mo", output:"\u2265", ttype:CONST}, +{input:"\\equiv", tag:"mo", output:"\u2261", ttype:CONST}, +{input:"\\ll", tag:"mo", output:"\u226A", ttype:CONST}, +{input:"\\gg", tag:"mo", output:"\u226B", ttype:CONST}, +{input:"\\doteq", tag:"mo", output:"\u2250", ttype:CONST}, +{input:"\\prec", tag:"mo", output:"\u227A", ttype:CONST}, +{input:"\\succ", tag:"mo", output:"\u227B", ttype:CONST}, +{input:"\\preceq", tag:"mo", output:"\u227C", ttype:CONST}, +{input:"\\succeq", tag:"mo", output:"\u227D", ttype:CONST}, +{input:"\\subset", tag:"mo", output:"\u2282", ttype:CONST}, +{input:"\\supset", tag:"mo", output:"\u2283", ttype:CONST}, +{input:"\\subseteq", tag:"mo", output:"\u2286", ttype:CONST}, +{input:"\\supseteq", tag:"mo", output:"\u2287", ttype:CONST}, +{input:"\\sqsubset", tag:"mo", output:"\u228F", ttype:CONST}, +{input:"\\sqsupset", tag:"mo", output:"\u2290", ttype:CONST}, +{input:"\\sqsubseteq", tag:"mo", output:"\u2291", ttype:CONST}, +{input:"\\sqsupseteq", tag:"mo", output:"\u2292", ttype:CONST}, +{input:"\\sim", tag:"mo", output:"\u223C", ttype:CONST}, +{input:"\\simeq", tag:"mo", output:"\u2243", ttype:CONST}, +{input:"\\approx", tag:"mo", output:"\u2248", ttype:CONST}, +{input:"\\cong", tag:"mo", output:"\u2245", ttype:CONST}, +{input:"\\Join", tag:"mo", output:"\u22C8", ttype:CONST}, +{input:"\\bowtie", tag:"mo", output:"\u22C8", ttype:CONST}, +{input:"\\in", tag:"mo", output:"\u2208", ttype:CONST}, +{input:"\\ni", tag:"mo", output:"\u220B", ttype:CONST}, +{input:"\\owns", tag:"mo", output:"\u220B", ttype:CONST}, +{input:"\\propto", tag:"mo", output:"\u221D", ttype:CONST}, +{input:"\\vdash", tag:"mo", output:"\u22A2", ttype:CONST}, +{input:"\\dashv", tag:"mo", output:"\u22A3", ttype:CONST}, +{input:"\\models", tag:"mo", output:"\u22A8", ttype:CONST}, +{input:"\\perp", tag:"mo", output:"\u22A5", ttype:CONST}, +{input:"\\smile", tag:"mo", output:"\u2323", ttype:CONST}, +{input:"\\frown", tag:"mo", output:"\u2322", ttype:CONST}, +{input:"\\asymp", tag:"mo", output:"\u224D", ttype:CONST}, +{input:"\\notin", tag:"mo", output:"\u2209", ttype:CONST}, + +//matrices +{input:"\\begin{eqnarray}", output:"X", ttype:MATRIX, invisible:true}, +{input:"\\begin{array}", output:"X", ttype:MATRIX, invisible:true}, +{input:"\\\\", output:"}&{", ttype:DEFINITION}, +{input:"\\end{eqnarray}", output:"}}", ttype:DEFINITION}, +{input:"\\end{array}", output:"}}", ttype:DEFINITION}, + +//grouping and literal brackets -- ieval is for IE +{input:"\\big", tag:"mo", output:"X", atval:"1.2", ieval:"2.2", ttype:BIG}, +{input:"\\Big", tag:"mo", output:"X", atval:"1.6", ieval:"2.6", ttype:BIG}, +{input:"\\bigg", tag:"mo", output:"X", atval:"2.2", ieval:"3.2", ttype:BIG}, +{input:"\\Bigg", tag:"mo", output:"X", atval:"2.9", ieval:"3.9", ttype:BIG}, +{input:"\\left", tag:"mo", output:"X", ttype:LEFTBRACKET}, +{input:"\\right", tag:"mo", output:"X", ttype:RIGHTBRACKET}, +{input:"{", output:"{", ttype:LEFTBRACKET, invisible:true}, +{input:"}", output:"}", ttype:RIGHTBRACKET, invisible:true}, + +{input:"(", tag:"mo", output:"(", atval:"1", ttype:STRETCHY}, +{input:"[", tag:"mo", output:"[", atval:"1", ttype:STRETCHY}, +{input:"\\lbrack", tag:"mo", output:"[", atval:"1", ttype:STRETCHY}, +{input:"\\{", tag:"mo", output:"{", atval:"1", ttype:STRETCHY}, +{input:"\\lbrace", tag:"mo", output:"{", atval:"1", ttype:STRETCHY}, +{input:"\\langle", tag:"mo", output:"\u2329", atval:"1", ttype:STRETCHY}, +{input:"\\lfloor", tag:"mo", output:"\u230A", atval:"1", ttype:STRETCHY}, +{input:"\\lceil", tag:"mo", output:"\u2308", atval:"1", ttype:STRETCHY}, + +// rtag:"mi" causes space to be inserted before a following sin, cos, etc. +// (see function AMparseExpr() ) +{input:")", tag:"mo",output:")", rtag:"mi",atval:"1",ttype:STRETCHY}, +{input:"]", tag:"mo",output:"]", rtag:"mi",atval:"1",ttype:STRETCHY}, +{input:"\\rbrack",tag:"mo",output:"]", rtag:"mi",atval:"1",ttype:STRETCHY}, +{input:"\\}", tag:"mo",output:"}", rtag:"mi",atval:"1",ttype:STRETCHY}, +{input:"\\rbrace",tag:"mo",output:"}", rtag:"mi",atval:"1",ttype:STRETCHY}, +{input:"\\rangle",tag:"mo",output:"\u232A", rtag:"mi",atval:"1",ttype:STRETCHY}, +{input:"\\rfloor",tag:"mo",output:"\u230B", rtag:"mi",atval:"1",ttype:STRETCHY}, +{input:"\\rceil", tag:"mo",output:"\u2309", rtag:"mi",atval:"1",ttype:STRETCHY}, + +// "|", "\\|", "\\vert" and "\\Vert" modified later: lspace = rspace = 0em +{input:"|", tag:"mo", output:"\u2223", atval:"1", ttype:STRETCHY}, +{input:"\\|", tag:"mo", output:"\u2225", atval:"1", ttype:STRETCHY}, +{input:"\\vert", tag:"mo", output:"\u2223", atval:"1", ttype:STRETCHY}, +{input:"\\Vert", tag:"mo", output:"\u2225", atval:"1", ttype:STRETCHY}, +{input:"\\mid", tag:"mo", output:"\u2223", atval:"1", ttype:STRETCHY}, +{input:"\\parallel", tag:"mo", output:"\u2225", atval:"1", ttype:STRETCHY}, +{input:"/", tag:"mo", output:"/", atval:"1.01", ttype:STRETCHY}, +{input:"\\backslash", tag:"mo", output:"\u2216", atval:"1", ttype:STRETCHY}, +{input:"\\setminus", tag:"mo", output:"\\", ttype:CONST}, + +//miscellaneous symbols +{input:"\\!", tag:"mspace", atname:"width", atval:"-0.167em", ttype:SPACE}, +{input:"\\,", tag:"mspace", atname:"width", atval:"0.167em", ttype:SPACE}, +{input:"\\>", tag:"mspace", atname:"width", atval:"0.222em", ttype:SPACE}, +{input:"\\:", tag:"mspace", atname:"width", atval:"0.222em", ttype:SPACE}, +{input:"\\;", tag:"mspace", atname:"width", atval:"0.278em", ttype:SPACE}, +{input:"~", tag:"mspace", atname:"width", atval:"0.333em", ttype:SPACE}, +{input:"\\quad", tag:"mspace", atname:"width", atval:"1em", ttype:SPACE}, +{input:"\\qquad", tag:"mspace", atname:"width", atval:"2em", ttype:SPACE}, +//{input:"{}", tag:"mo", output:"\u200B", ttype:CONST}, // zero-width +{input:"\\prime", tag:"mo", output:"\u2032", ttype:CONST}, +{input:"'", tag:"mo", output:"\u02B9", ttype:CONST}, +{input:"''", tag:"mo", output:"\u02BA", ttype:CONST}, +{input:"'''", tag:"mo", output:"\u2034", ttype:CONST}, +{input:"''''", tag:"mo", output:"\u2057", ttype:CONST}, +{input:"\\ldots", tag:"mo", output:"\u2026", ttype:CONST}, +{input:"\\cdots", tag:"mo", output:"\u22EF", ttype:CONST}, +{input:"\\vdots", tag:"mo", output:"\u22EE", ttype:CONST}, +{input:"\\ddots", tag:"mo", output:"\u22F1", ttype:CONST}, +{input:"\\forall", tag:"mo", output:"\u2200", ttype:CONST}, +{input:"\\exists", tag:"mo", output:"\u2203", ttype:CONST}, +{input:"\\Re", tag:"mo", output:"\u211C", ttype:CONST}, +{input:"\\Im", tag:"mo", output:"\u2111", ttype:CONST}, +{input:"\\aleph", tag:"mo", output:"\u2135", ttype:CONST}, +{input:"\\hbar", tag:"mo", output:"\u210F", ttype:CONST}, +{input:"\\ell", tag:"mo", output:"\u2113", ttype:CONST}, +{input:"\\wp", tag:"mo", output:"\u2118", ttype:CONST}, +{input:"\\emptyset", tag:"mo", output:"\u2205", ttype:CONST}, +{input:"\\infty", tag:"mo", output:"\u221E", ttype:CONST}, +{input:"\\surd", tag:"mo", output:"\\sqrt{}", ttype:DEFINITION}, +{input:"\\partial", tag:"mo", output:"\u2202", ttype:CONST}, +{input:"\\nabla", tag:"mo", output:"\u2207", ttype:CONST}, +{input:"\\triangle", tag:"mo", output:"\u25B3", ttype:CONST}, +{input:"\\therefore", tag:"mo", output:"\u2234", ttype:CONST}, +{input:"\\angle", tag:"mo", output:"\u2220", ttype:CONST}, +//{input:"\\\\ ", tag:"mo", output:"\u00A0", ttype:CONST}, +{input:"\\diamond", tag:"mo", output:"\u22C4", ttype:CONST}, +//{input:"\\Diamond", tag:"mo", output:"\u25CA", ttype:CONST}, +{input:"\\Diamond", tag:"mo", output:"\u25C7", ttype:CONST}, +{input:"\\neg", tag:"mo", output:"\u00AC", ttype:CONST}, +{input:"\\lnot", tag:"mo", output:"\u00AC", ttype:CONST}, +{input:"\\bot", tag:"mo", output:"\u22A5", ttype:CONST}, +{input:"\\top", tag:"mo", output:"\u22A4", ttype:CONST}, +{input:"\\square", tag:"mo", output:"\u25AB", ttype:CONST}, +{input:"\\Box", tag:"mo", output:"\u25A1", ttype:CONST}, +{input:"\\wr", tag:"mo", output:"\u2240", ttype:CONST}, + +//standard functions +//Note UNDEROVER *must* have tag:"mo" to work properly +{input:"\\arccos", tag:"mi", output:"arccos", ttype:UNARY, func:true}, +{input:"\\arcsin", tag:"mi", output:"arcsin", ttype:UNARY, func:true}, +{input:"\\arctan", tag:"mi", output:"arctan", ttype:UNARY, func:true}, +{input:"\\arg", tag:"mi", output:"arg", ttype:UNARY, func:true}, +{input:"\\cos", tag:"mi", output:"cos", ttype:UNARY, func:true}, +{input:"\\cosh", tag:"mi", output:"cosh", ttype:UNARY, func:true}, +{input:"\\cot", tag:"mi", output:"cot", ttype:UNARY, func:true}, +{input:"\\coth", tag:"mi", output:"coth", ttype:UNARY, func:true}, +{input:"\\csc", tag:"mi", output:"csc", ttype:UNARY, func:true}, +{input:"\\deg", tag:"mi", output:"deg", ttype:UNARY, func:true}, +{input:"\\det", tag:"mi", output:"det", ttype:UNARY, func:true}, +{input:"\\dim", tag:"mi", output:"dim", ttype:UNARY, func:true}, //CONST? +{input:"\\exp", tag:"mi", output:"exp", ttype:UNARY, func:true}, +{input:"\\gcd", tag:"mi", output:"gcd", ttype:UNARY, func:true}, //CONST? +{input:"\\hom", tag:"mi", output:"hom", ttype:UNARY, func:true}, +{input:"\\inf", tag:"mo", output:"inf", ttype:UNDEROVER}, +{input:"\\ker", tag:"mi", output:"ker", ttype:UNARY, func:true}, +{input:"\\lg", tag:"mi", output:"lg", ttype:UNARY, func:true}, +{input:"\\lim", tag:"mo", output:"lim", ttype:UNDEROVER}, +{input:"\\liminf", tag:"mo", output:"liminf", ttype:UNDEROVER}, +{input:"\\limsup", tag:"mo", output:"limsup", ttype:UNDEROVER}, +{input:"\\ln", tag:"mi", output:"ln", ttype:UNARY, func:true}, +{input:"\\log", tag:"mi", output:"log", ttype:UNARY, func:true}, +{input:"\\max", tag:"mo", output:"max", ttype:UNDEROVER}, +{input:"\\min", tag:"mo", output:"min", ttype:UNDEROVER}, +{input:"\\Pr", tag:"mi", output:"Pr", ttype:UNARY, func:true}, +{input:"\\sec", tag:"mi", output:"sec", ttype:UNARY, func:true}, +{input:"\\sin", tag:"mi", output:"sin", ttype:UNARY, func:true}, +{input:"\\sinh", tag:"mi", output:"sinh", ttype:UNARY, func:true}, +{input:"\\sup", tag:"mo", output:"sup", ttype:UNDEROVER}, +{input:"\\tan", tag:"mi", output:"tan", ttype:UNARY, func:true}, +{input:"\\tanh", tag:"mi", output:"tanh", ttype:UNARY, func:true}, + +//arrows +{input:"\\gets", tag:"mo", output:"\u2190", ttype:CONST}, +{input:"\\leftarrow", tag:"mo", output:"\u2190", ttype:CONST}, +{input:"\\to", tag:"mo", output:"\u2192", ttype:CONST}, +{input:"\\rightarrow", tag:"mo", output:"\u2192", ttype:CONST}, +{input:"\\leftrightarrow", tag:"mo", output:"\u2194", ttype:CONST}, +{input:"\\uparrow", tag:"mo", output:"\u2191", ttype:CONST}, +{input:"\\downarrow", tag:"mo", output:"\u2193", ttype:CONST}, +{input:"\\updownarrow", tag:"mo", output:"\u2195", ttype:CONST}, +{input:"\\Leftarrow", tag:"mo", output:"\u21D0", ttype:CONST}, +{input:"\\Rightarrow", tag:"mo", output:"\u21D2", ttype:CONST}, +{input:"\\Leftrightarrow", tag:"mo", output:"\u21D4", ttype:CONST}, +{input:"\\iff", tag:"mo", output:"~\\Longleftrightarrow~", ttype:DEFINITION}, +{input:"\\Uparrow", tag:"mo", output:"\u21D1", ttype:CONST}, +{input:"\\Downarrow", tag:"mo", output:"\u21D3", ttype:CONST}, +{input:"\\Updownarrow", tag:"mo", output:"\u21D5", ttype:CONST}, +{input:"\\mapsto", tag:"mo", output:"\u21A6", ttype:CONST}, +{input:"\\longleftarrow", tag:"mo", output:"\u2190", ttype:LONG}, +{input:"\\longrightarrow", tag:"mo", output:"\u2192", ttype:LONG}, +{input:"\\longleftrightarrow", tag:"mo", output:"\u2194", ttype:LONG}, +{input:"\\Longleftarrow", tag:"mo", output:"\u21D0", ttype:LONG}, +{input:"\\Longrightarrow", tag:"mo", output:"\u21D2", ttype:LONG}, +{input:"\\Longleftrightarrow", tag:"mo", output:"\u21D4", ttype:LONG}, +{input:"\\longmapsto", tag:"mo", output:"\u21A6", ttype:CONST}, + // disaster if LONG + +//commands with argument +AMsqrt, AMroot, AMfrac, AMover, AMsub, AMsup, AMtext, AMmbox, AMatop, AMchoose, +//AMdiv, AMquote, + +//diacritical marks +{input:"\\acute", tag:"mover", output:"\u00B4", ttype:UNARY, acc:true}, +//{input:"\\acute", tag:"mover", output:"\u0317", ttype:UNARY, acc:true}, +//{input:"\\acute", tag:"mover", output:"\u0301", ttype:UNARY, acc:true}, +//{input:"\\grave", tag:"mover", output:"\u0300", ttype:UNARY, acc:true}, +//{input:"\\grave", tag:"mover", output:"\u0316", ttype:UNARY, acc:true}, +{input:"\\grave", tag:"mover", output:"\u0060", ttype:UNARY, acc:true}, +{input:"\\breve", tag:"mover", output:"\u02D8", ttype:UNARY, acc:true}, +{input:"\\check", tag:"mover", output:"\u02C7", ttype:UNARY, acc:true}, +{input:"\\dot", tag:"mover", output:".", ttype:UNARY, acc:true}, +{input:"\\ddot", tag:"mover", output:"..", ttype:UNARY, acc:true}, +//{input:"\\ddot", tag:"mover", output:"\u00A8", ttype:UNARY, acc:true}, +{input:"\\mathring", tag:"mover", output:"\u00B0", ttype:UNARY, acc:true}, +{input:"\\vec", tag:"mover", output:"\u20D7", ttype:UNARY, acc:true}, +{input:"\\overrightarrow",tag:"mover",output:"\u20D7", ttype:UNARY, acc:true}, +{input:"\\overleftarrow",tag:"mover", output:"\u20D6", ttype:UNARY, acc:true}, +{input:"\\hat", tag:"mover", output:"\u005E", ttype:UNARY, acc:true}, +{input:"\\widehat", tag:"mover", output:"\u0302", ttype:UNARY, acc:true}, +{input:"\\tilde", tag:"mover", output:"~", ttype:UNARY, acc:true}, +//{input:"\\tilde", tag:"mover", output:"\u0303", ttype:UNARY, acc:true}, +{input:"\\widetilde", tag:"mover", output:"\u02DC", ttype:UNARY, acc:true}, +{input:"\\bar", tag:"mover", output:"\u203E", ttype:UNARY, acc:true}, +{input:"\\overbrace", tag:"mover", output:"\u23B4", ttype:UNARY, acc:true}, +{input:"\\overline", tag:"mover", output:"\u00AF", ttype:UNARY, acc:true}, +{input:"\\underbrace", tag:"munder", output:"\u23B5", ttype:UNARY, acc:true}, +{input:"\\underline", tag:"munder", output:"\u00AF", ttype:UNARY, acc:true}, +//{input:"underline", tag:"munder", output:"\u0332", ttype:UNARY, acc:true}, + +//typestyles and fonts +{input:"\\displaystyle",tag:"mstyle",atname:"displaystyle",atval:"true", ttype:UNARY}, +{input:"\\textstyle",tag:"mstyle",atname:"displaystyle",atval:"false", ttype:UNARY}, +{input:"\\scriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"1", ttype:UNARY}, +{input:"\\scriptscriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"2", ttype:UNARY}, +{input:"\\textrm", tag:"mstyle", output:"\\mathrm", ttype: DEFINITION}, +{input:"\\mathbf", tag:"mstyle", atname:"mathvariant", atval:"bold", ttype:UNARY}, +{input:"\\textbf", tag:"mstyle", atname:"mathvariant", atval:"bold", ttype:UNARY}, +{input:"\\mathit", tag:"mstyle", atname:"mathvariant", atval:"italic", ttype:UNARY}, +{input:"\\textit", tag:"mstyle", atname:"mathvariant", atval:"italic", ttype:UNARY}, +{input:"\\mathtt", tag:"mstyle", atname:"mathvariant", atval:"monospace", ttype:UNARY}, +{input:"\\texttt", tag:"mstyle", atname:"mathvariant", atval:"monospace", ttype:UNARY}, +{input:"\\mathsf", tag:"mstyle", atname:"mathvariant", atval:"sans-serif", ttype:UNARY}, +{input:"\\mathbb", tag:"mstyle", atname:"mathvariant", atval:"double-struck", ttype:UNARY, codes:AMbbb}, +{input:"\\mathcal",tag:"mstyle", atname:"mathvariant", atval:"script", ttype:UNARY, codes:AMcal}, +{input:"\\mathfrak",tag:"mstyle",atname:"mathvariant", atval:"fraktur",ttype:UNARY, codes:AMfrk} +]; + +function compareNames(s1,s2) { + if (s1.input > s2.input) return 1 + else return -1; +} + +var AMnames = []; //list of input symbols + +function AMinitSymbols() { + AMsymbols.sort(compareNames); + for (i=0; i=n where str appears or would be inserted +// assumes arr is sorted + if (n==0) { + var h,m; + n = -1; + h = arr.length; + while (n+1> 1; + if (arr[m]=str +} + +function AMgetSymbol(str) { +//return maximal initial substring of str that appears in names +//return null if there is none + var k = 0; //new pos + var j = 0; //old pos + var mk; //match pos + var st; + var tagst; + var match = ""; + var more = true; + for (var i=1; i<=str.length && more; i++) { + st = str.slice(0,i); //initial substring of length i + j = k; + k = AMposition(AMnames, st, j); + if (k=AMnames[k]; + } + AMpreviousSymbol=AMcurrentSymbol; + if (match!=""){ + AMcurrentSymbol=AMsymbols[mk].ttype; + return AMsymbols[mk]; + } + AMcurrentSymbol=CONST; + k = 1; + st = str.slice(0,1); //take 1 character + if ("0"<=st && st<="9") tagst = "mn"; + else tagst = (("A">st || st>"Z") && ("a">st || st>"z")?"mo":"mi"); +/* +// Commented out by DRW (not fully understood, but probably to do with +// use of "/" as an INFIX version of "\\frac", which we don't want): +//} +//if (st=="-" && AMpreviousSymbol==INFIX) { +// AMcurrentSymbol = INFIX; //trick "/" into recognizing "-" on second parse +// return {input:st, tag:tagst, output:st, ttype:UNARY, func:true}; +//} +*/ + return {input:st, tag:tagst, output:st, ttype:CONST}; +} + + +/*Parsing ASCII math expressions with the following grammar +v ::= [A-Za-z] | greek letters | numbers | other constant symbols +u ::= sqrt | text | bb | other unary symbols for font commands +b ::= frac | root | stackrel binary symbols +l ::= { | \left left brackets +r ::= } | \right right brackets +S ::= v | lEr | uS | bSS Simple expression +I ::= S_S | S^S | S_S^S | S Intermediate expression +E ::= IE | I/I Expression +Each terminal symbol is translated into a corresponding mathml node.*/ + +var AMpreviousSymbol,AMcurrentSymbol; + +function AMparseSexpr(str) { //parses str and returns [node,tailstr,(node)tag] + var symbol, node, result, result2, i, st,// rightvert = false, + newFrag = document.createDocumentFragment(); + str = AMremoveCharsAndBlanks(str,0); + symbol = AMgetSymbol(str); //either a token or a bracket or empty + if (symbol == null || symbol.ttype == RIGHTBRACKET) + return [null,str,null]; + if (symbol.ttype == DEFINITION) { + str = symbol.output+AMremoveCharsAndBlanks(str,symbol.input.length); + symbol = AMgetSymbol(str); + if (symbol == null || symbol.ttype == RIGHTBRACKET) + return [null,str,null]; + } + str = AMremoveCharsAndBlanks(str,symbol.input.length); + switch (symbol.ttype) { + case SPACE: + node = AMcreateElementMathML(symbol.tag); + node.setAttribute(symbol.atname,symbol.atval); + return [node,str,symbol.tag]; + case UNDEROVER: + if (isIE) { + if (symbol.input.substr(0,4) == "\\big") { // botch for missing symbols + str = "\\"+symbol.input.substr(4)+str; // make \bigcup = \cup etc. + symbol = AMgetSymbol(str); + symbol.ttype = UNDEROVER; + str = AMremoveCharsAndBlanks(str,symbol.input.length); + } + } + return [AMcreateMmlNode(symbol.tag, + document.createTextNode(symbol.output)),str,symbol.tag]; + case CONST: + var output = symbol.output; + if (isIE) { + if (symbol.input == "'") + output = "\u2032"; + else if (symbol.input == "''") + output = "\u2033"; + else if (symbol.input == "'''") + output = "\u2033\u2032"; + else if (symbol.input == "''''") + output = "\u2033\u2033"; + else if (symbol.input == "\\square") + output = "\u25A1"; // same as \Box + else if (symbol.input.substr(0,5) == "\\frac") { + // botch for missing fractions + var denom = symbol.input.substr(6,1); + if (denom == "5" || denom == "6") { + str = symbol.input.replace(/\\frac/,"\\frac ")+str; + return [node,str,symbol.tag]; + } + } + } + node = AMcreateMmlNode(symbol.tag,document.createTextNode(output)); + return [node,str,symbol.tag]; + case LONG: // added by DRW + node = AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)); + node.setAttribute("minsize","1.5"); + node.setAttribute("maxsize","1.5"); + node = AMcreateMmlNode("mover",node); + node.appendChild(AMcreateElementMathML("mspace")); + return [node,str,symbol.tag]; + case STRETCHY: // added by DRW + if (isIE && symbol.input == "\\backslash") + symbol.output = "\\"; // doesn't expand, but then nor does "\u2216" + node = AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)); + if (symbol.input == "|" || symbol.input == "\\vert" || + symbol.input == "\\|" || symbol.input == "\\Vert") { + node.setAttribute("lspace","0em"); + node.setAttribute("rspace","0em"); + } + node.setAttribute("maxsize",symbol.atval); // don't allow to stretch here + if (symbol.rtag != null) + return [node,str,symbol.rtag]; + else + return [node,str,symbol.tag]; + case BIG: // added by DRW + var atval = symbol.atval; + if (isIE) + atval = symbol.ieval; + symbol = AMgetSymbol(str); + if (symbol == null) + return [null,str,null]; + str = AMremoveCharsAndBlanks(str,symbol.input.length); + node = AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)); + if (isIE) { // to get brackets to expand + var space = AMcreateElementMathML("mspace"); + space.setAttribute("height",atval+"ex"); + node = AMcreateMmlNode("mrow",node); + node.appendChild(space); + } else { // ignored in IE + node.setAttribute("minsize",atval); + node.setAttribute("maxsize",atval); + } + return [node,str,symbol.tag]; + case LEFTBRACKET: //read (expr+) + if (symbol.input == "\\left") { // left what? + symbol = AMgetSymbol(str); + if (symbol != null) { + if (symbol.input == ".") + symbol.invisible = true; + str = AMremoveCharsAndBlanks(str,symbol.input.length); + } + } + result = AMparseExpr(str,true,false); + if (symbol==null || + (typeof symbol.invisible == "boolean" && symbol.invisible)) + node = AMcreateMmlNode("mrow",result[0]); + else { + node = AMcreateMmlNode("mo",document.createTextNode(symbol.output)); + node = AMcreateMmlNode("mrow",node); + node.appendChild(result[0]); + } + return [node,result[1],result[2]]; + case MATRIX: //read (expr+) + if (symbol.input == "\\begin{array}") { + var mask = ""; + symbol = AMgetSymbol(str); + str = AMremoveCharsAndBlanks(str,0); + if (symbol == null) + mask = "l"; + else { + str = AMremoveCharsAndBlanks(str,symbol.input.length); + if (symbol.input != "{") + mask = "l"; + else do { + symbol = AMgetSymbol(str); + if (symbol != null) { + str = AMremoveCharsAndBlanks(str,symbol.input.length); + if (symbol.input != "}") + mask = mask+symbol.input; + } + } while (symbol != null && symbol.input != "" && symbol.input != "}"); + } + result = AMparseExpr("{"+str,true,true); +// if (result[0]==null) return [AMcreateMmlNode("mo", +// document.createTextNode(symbol.input)),str]; + node = AMcreateMmlNode("mtable",result[0]); + mask = mask.replace(/l/g,"left "); + mask = mask.replace(/r/g,"right "); + mask = mask.replace(/c/g,"center "); + node.setAttribute("columnalign",mask); + node.setAttribute("displaystyle","false"); + if (isIE) + return [node,result[1],null]; +// trying to get a *little* bit of space around the array +// (IE already includes it) + var lspace = AMcreateElementMathML("mspace"); + lspace.setAttribute("width","0.167em"); + var rspace = AMcreateElementMathML("mspace"); + rspace.setAttribute("width","0.167em"); + var node1 = AMcreateMmlNode("mrow",lspace); + node1.appendChild(node); + node1.appendChild(rspace); + return [node1,result[1],null]; + } else { // eqnarray + result = AMparseExpr("{"+str,true,true); + node = AMcreateMmlNode("mtable",result[0]); + if (isIE) + node.setAttribute("columnspacing","0.25em"); // best in practice? + else + node.setAttribute("columnspacing","0.167em"); // correct (but ignored?) + node.setAttribute("columnalign","right center left"); + node.setAttribute("displaystyle","true"); + node = AMcreateMmlNode("mrow",node); + return [node,result[1],null]; + } + case TEXT: + if (str.charAt(0)=="{") i=str.indexOf("}"); + else i = 0; + if (i==-1) + i = str.length; + st = str.slice(1,i); + if (st.charAt(0) == " ") { + node = AMcreateElementMathML("mspace"); + node.setAttribute("width","0.33em"); // was 1ex + newFrag.appendChild(node); + } + newFrag.appendChild( + AMcreateMmlNode(symbol.tag,document.createTextNode(st))); + if (st.charAt(st.length-1) == " ") { + node = AMcreateElementMathML("mspace"); + node.setAttribute("width","0.33em"); // was 1ex + newFrag.appendChild(node); + } + str = AMremoveCharsAndBlanks(str,i+1); + return [AMcreateMmlNode("mrow",newFrag),str,null]; + case UNARY: + result = AMparseSexpr(str); + if (result[0]==null) return [AMcreateMmlNode(symbol.tag, + document.createTextNode(symbol.output)),str]; + if (typeof symbol.func == "boolean" && symbol.func) { // functions hack + st = str.charAt(0); +// if (st=="^" || st=="_" || st=="/" || st=="|" || st==",") { + if (st=="^" || st=="_" || st==",") { + return [AMcreateMmlNode(symbol.tag, + document.createTextNode(symbol.output)),str,symbol.tag]; + } else { + node = AMcreateMmlNode("mrow", + AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output))); + if (isIE) { + var space = AMcreateElementMathML("mspace"); + space.setAttribute("width","0.167em"); + node.appendChild(space); + } + node.appendChild(result[0]); + return [node,result[1],symbol.tag]; + } + } + if (symbol.input == "\\sqrt") { // sqrt + if (isIE) { // set minsize, for \surd + var space = AMcreateElementMathML("mspace"); + space.setAttribute("height","1.2ex"); + space.setAttribute("width","0em"); // probably no effect + node = AMcreateMmlNode(symbol.tag,result[0]) +// node.setAttribute("minsize","1"); // ignored +// node = AMcreateMmlNode("mrow",node); // hopefully unnecessary + node.appendChild(space); + return [node,result[1],symbol.tag]; + } else + return [AMcreateMmlNode(symbol.tag,result[0]),result[1],symbol.tag]; + } else if (typeof symbol.acc == "boolean" && symbol.acc) { // accent + node = AMcreateMmlNode(symbol.tag,result[0]); + var output = symbol.output; + if (isIE) { + if (symbol.input == "\\hat") + output = "\u0302"; + else if (symbol.input == "\\widehat") + output = "\u005E"; + else if (symbol.input == "\\bar") + output = "\u00AF"; + else if (symbol.input == "\\grave") + output = "\u0300"; + else if (symbol.input == "\\tilde") + output = "\u0303"; + } + var node1 = AMcreateMmlNode("mo",document.createTextNode(output)); + if (symbol.input == "\\vec" || symbol.input == "\\check") + // don't allow to stretch + node1.setAttribute("maxsize","1.2"); + // why doesn't "1" work? \vec nearly disappears in firefox + if (isIE && symbol.input == "\\bar") + node1.setAttribute("maxsize","0.5"); + if (symbol.input == "\\underbrace" || symbol.input == "\\underline") + node1.setAttribute("accentunder","true"); + else + node1.setAttribute("accent","true"); + node.appendChild(node1); + if (symbol.input == "\\overbrace" || symbol.input == "\\underbrace") + node.ttype = UNDEROVER; + return [node,result[1],symbol.tag]; + } else { // font change or displaystyle command + if (!isIE && typeof symbol.codes != "undefined") { + for (i=0; i64 && st.charCodeAt(j)<91) newst = newst + + String.fromCharCode(symbol.codes[st.charCodeAt(j)-65]); + else newst = newst + st.charAt(j); + if (result[0].nodeName=="mi") + result[0]=AMcreateElementMathML("mo"). + appendChild(document.createTextNode(newst)); + else result[0].replaceChild(AMcreateElementMathML("mo"). + appendChild(document.createTextNode(newst)),result[0].childNodes[i]); + } + } + node = AMcreateMmlNode(symbol.tag,result[0]); + node.setAttribute(symbol.atname,symbol.atval); + if (symbol.input == "\\scriptstyle" || + symbol.input == "\\scriptscriptstyle") + node.setAttribute("displaystyle","false"); + return [node,result[1],symbol.tag]; + } + case BINARY: + result = AMparseSexpr(str); + if (result[0]==null) return [AMcreateMmlNode("mo", + document.createTextNode(symbol.input)),str,null]; + result2 = AMparseSexpr(result[1]); + if (result2[0]==null) return [AMcreateMmlNode("mo", + document.createTextNode(symbol.input)),str,null]; + if (symbol.input=="\\root" || symbol.input=="\\stackrel") + newFrag.appendChild(result2[0]); + newFrag.appendChild(result[0]); + if (symbol.input=="\\frac") newFrag.appendChild(result2[0]); + return [AMcreateMmlNode(symbol.tag,newFrag),result2[1],symbol.tag]; + case INFIX: + str = AMremoveCharsAndBlanks(str,symbol.input.length); + return [AMcreateMmlNode("mo",document.createTextNode(symbol.output)), + str,symbol.tag]; + default: + return [AMcreateMmlNode(symbol.tag, //its a constant + document.createTextNode(symbol.output)),str,symbol.tag]; + } +} + +function AMparseIexpr(str) { + var symbol, sym1, sym2, node, result, tag, underover; + str = AMremoveCharsAndBlanks(str,0); + sym1 = AMgetSymbol(str); + result = AMparseSexpr(str); + node = result[0]; + str = result[1]; + tag = result[2]; + symbol = AMgetSymbol(str); + if (symbol.ttype == INFIX) { + str = AMremoveCharsAndBlanks(str,symbol.input.length); + result = AMparseSexpr(str); + if (result[0] == null) // show box in place of missing argument + result[0] = AMcreateMmlNode("mo",document.createTextNode("\u25A1")); + str = result[1]; + tag = result[2]; + if (symbol.input == "_" || symbol.input == "^") { + sym2 = AMgetSymbol(str); + tag = null; // no space between x^2 and a following sin, cos, etc. +// This is for \underbrace and \overbrace + underover = ((sym1.ttype == UNDEROVER) || (node.ttype == UNDEROVER)); +// underover = (sym1.ttype == UNDEROVER); + if (symbol.input == "_" && sym2.input == "^") { + str = AMremoveCharsAndBlanks(str,sym2.input.length); + var res2 = AMparseSexpr(str); + str = res2[1]; + tag = res2[2]; // leave space between x_1^2 and a following sin etc. + node = AMcreateMmlNode((underover?"munderover":"msubsup"),node); + node.appendChild(result[0]); + node.appendChild(res2[0]); + } else if (symbol.input == "_") { + node = AMcreateMmlNode((underover?"munder":"msub"),node); + node.appendChild(result[0]); + } else { + node = AMcreateMmlNode((underover?"mover":"msup"),node); + node.appendChild(result[0]); + } + node = AMcreateMmlNode("mrow",node); // so sum does not stretch + } else { + node = AMcreateMmlNode(symbol.tag,node); + if (symbol.input == "\\atop" || symbol.input == "\\choose") + node.setAttribute("linethickness","0ex"); + node.appendChild(result[0]); + if (symbol.input == "\\choose") + node = AMcreateMmlNode("mfenced",node); + } + } + return [node,str,tag]; +} + +function AMparseExpr(str,rightbracket,matrix) { + var symbol, node, result, i, tag, + newFrag = document.createDocumentFragment(); + do { + str = AMremoveCharsAndBlanks(str,0); + result = AMparseIexpr(str); + node = result[0]; + str = result[1]; + tag = result[2]; + symbol = AMgetSymbol(str); + if (node!=undefined) { + if ((tag == "mn" || tag == "mi") && symbol!=null && + typeof symbol.func == "boolean" && symbol.func) { + // Add space before \sin in 2\sin x or x\sin x + var space = AMcreateElementMathML("mspace"); + space.setAttribute("width","0.167em"); + node = AMcreateMmlNode("mrow",node); + node.appendChild(space); + } + newFrag.appendChild(node); + } + } while ((symbol.ttype != RIGHTBRACKET) + && symbol!=null && symbol.output!=""); + tag = null; + if (symbol.ttype == RIGHTBRACKET) { + if (symbol.input == "\\right") { // right what? + str = AMremoveCharsAndBlanks(str,symbol.input.length); + symbol = AMgetSymbol(str); + if (symbol != null && symbol.input == ".") + symbol.invisible = true; + if (symbol != null) + tag = symbol.rtag; + } + if (symbol!=null) + str = AMremoveCharsAndBlanks(str,symbol.input.length); // ready to return + var len = newFrag.childNodes.length; + if (matrix && + len>0 && newFrag.childNodes[len-1].nodeName == "mrow" && len>1 && + newFrag.childNodes[len-2].nodeName == "mo" && + newFrag.childNodes[len-2].firstChild.nodeValue == "&") { //matrix + var pos = []; // positions of ampersands + var m = newFrag.childNodes.length; + for (i=0; matrix && i -&-&...&-&- + n = node.childNodes.length; + k = 0; + for (j=0; j2) { + newFrag.removeChild(newFrag.firstChild); //remove + newFrag.removeChild(newFrag.firstChild); //remove & + } + table.appendChild(AMcreateMmlNode("mtr",row)); + } + return [table,str]; + } + if (typeof symbol.invisible != "boolean" || !symbol.invisible) { + node = AMcreateMmlNode("mo",document.createTextNode(symbol.output)); + newFrag.appendChild(node); + } + } + return [newFrag,str,tag]; +} + +function AMparseMath(str) { + var result, node = AMcreateElementMathML("mstyle"); + if (mathcolor != "") node.setAttribute("mathcolor",mathcolor); + if (mathfontfamily != "") node.setAttribute("fontfamily",mathfontfamily); + node.appendChild(AMparseExpr(str.replace(/^\s+/g,""),false,false)[0]); + node = AMcreateMmlNode("math",node); + if (showasciiformulaonhover) //fixed by djhsu so newline + node.setAttribute("title",str.replace(/\s+/g," "));//does not show in Gecko + if (mathfontfamily != "" && (isIE || mathfontfamily != "serif")) { + var fnode = AMcreateElementXHTML("font"); + fnode.setAttribute("face",mathfontfamily); + fnode.appendChild(node); + return fnode; + } + return node; +} + +function AMstrarr2docFrag(arr, linebreaks) { + var newFrag=document.createDocumentFragment(); + var expr = false; + for (var i=0; i1 || mtch) { + if (checkForMathML) { + checkForMathML = false; + var nd = AMisMathMLavailable(); + AMnoMathML = nd != null; + if (AMnoMathML && notifyIfNoMathML) + if (alertIfNoMathML) + alert("To view the ASCIIMathML notation use Internet Explorer 6 +\nMathPlayer (free from www.dessci.com)\n\ + or Firefox/Mozilla/Netscape"); + else AMbody.insertBefore(nd,AMbody.childNodes[0]); + } + if (!AMnoMathML) { + frg = AMstrarr2docFrag(arr,n.nodeType==8); + var len = frg.childNodes.length; + n.parentNode.replaceChild(frg,n); + return len-1; + } else return 0; + } + } + } else return 0; + } else if (n.nodeName!="math") { + for (i=0; i"); + document.write(""); +} + +// GO1.1 Generic onload by Brothercake +// http://www.brothercake.com/ +//onload function (replaces the onload="translate()" in the tag) +function generic() +{ + translate(); +}; +//setup onload function +if(typeof window.addEventListener != 'undefined') +{ + //.. gecko, safari, konqueror and standard + window.addEventListener('load', generic, false); +} +else if(typeof document.addEventListener != 'undefined') +{ + //.. opera 7 + document.addEventListener('load', generic, false); +} +else if(typeof window.attachEvent != 'undefined') +{ + //.. win/ie + window.attachEvent('onload', generic); +} +//** remove this condition to degrade older browsers +else +{ + //.. mac/ie5 and anything else that gets this far + //if there's an existing onload function + if(typeof window.onload == 'function') + { + //store it + var existing = onload; + //add new onload handler + window.onload = function() + { + //call existing onload function + existing(); + //call generic onload function + generic(); + }; + } + else + { + //setup onload function + window.onload = generic; + } +} diff --git a/stylesheets/javascripts/asciidoc.js b/stylesheets/javascripts/asciidoc.js new file mode 100644 index 0000000..ac36563 --- /dev/null +++ b/stylesheets/javascripts/asciidoc.js @@ -0,0 +1,189 @@ +var asciidoc = { // Namespace. + +///////////////////////////////////////////////////////////////////// +// Table Of Contents generator +///////////////////////////////////////////////////////////////////// + +/* Author: Mihai Bazon, September 2002 + * http://students.infoiasi.ro/~mishoo + * + * Table Of Content generator + * Version: 0.4 + * + * Feel free to use this script under the terms of the GNU General Public + * License, as long as you do not remove or alter this notice. + */ + + /* modified by Troy D. Hanson, September 2006. License: GPL */ + /* modified by Stuart Rackham, 2006, 2009. License: GPL */ + +// toclevels = 1..4. +toc: function (toclevels) { + + function getText(el) { + var text = ""; + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants. + text += i.data; + else if (i.firstChild != null) + text += getText(i); + } + return text; + } + + function TocEntry(el, text, toclevel) { + this.element = el; + this.text = text; + this.toclevel = toclevel; + } + + function tocEntries(el, toclevels) { + var result = new Array; + var re = new RegExp('[hH]([1-'+(toclevels+1)+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + if (!toc) { + return; + } + + // Delete existing TOC entries in case we're reloading the TOC. + var tocEntriesToRemove = []; + var i; + for (i = 0; i < toc.childNodes.length; i++) { + var entry = toc.childNodes[i]; + if (entry.nodeName.toLowerCase() == 'div' + && entry.getAttribute("class") + && entry.getAttribute("class").match(/^toclevel/)) + tocEntriesToRemove.push(entry); + } + for (i = 0; i < tocEntriesToRemove.length; i++) { + toc.removeChild(tocEntriesToRemove[i]); + } + + // Rebuild TOC entries. + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + // Delete existing footnote entries in case we're reloading the footnodes. + var i; + var noteholder = document.getElementById("footnotes"); + if (!noteholder) { + return; + } + var entriesToRemove = []; + for (i = 0; i < noteholder.childNodes.length; i++) { + var entry = noteholder.childNodes[i]; + if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote") + entriesToRemove.push(entry); + } + for (i = 0; i < entriesToRemove.length; i++) { + noteholder.removeChild(entriesToRemove[i]); + } + + // Rebuild footnote entries. + var cont = document.getElementById("content"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i" + n + "]"; + spans[i].setAttribute("data-note", note); + } + noteholder.innerHTML += + "
" + + "" + + n + ". " + note + "
"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i" + n + "]"; + } + } + } +}, + +install: function(toclevels) { + var timerId; + + function reinstall() { + asciidoc.footnotes(); + if (toclevels) { + asciidoc.toc(toclevels); + } + } + + function reinstallAndRemoveTimer() { + clearInterval(timerId); + reinstall(); + } + + timerId = setInterval(reinstall, 500); + if (document.addEventListener) + document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false); + else + window.onload = reinstallAndRemoveTimer; +} + +} diff --git a/stylesheets/javascripts/slidy.js b/stylesheets/javascripts/slidy.js new file mode 100644 index 0000000..f7ffcca --- /dev/null +++ b/stylesheets/javascripts/slidy.js @@ -0,0 +1,2848 @@ +/* slidy.js + + Copyright (c) 2005-2010 W3C (MIT, ERCIM, Keio), All Rights Reserved. + W3C liability, trademark, document use and software licensing + rules apply, see: + + http://www.w3.org/Consortium/Legal/copyright-documents + http://www.w3.org/Consortium/Legal/copyright-software +*/ + +// the slidy object implementation +var w3c_slidy = { + // classify which kind of browser we're running under + ns_pos: (typeof window.pageYOffset!='undefined'), + khtml: ((navigator.userAgent).indexOf("KHTML") >= 0 ? true : false), + opera: ((navigator.userAgent).indexOf("Opera") >= 0 ? true : false), + ipad: ((navigator.userAgent).indexOf("iPad") >= 0 ? true : false), + iphone: ((navigator.userAgent).indexOf("iPhone") >= 0 ? true : false), + ie: (typeof document.all != "undefined" && !this.opera), + ie6: (!this.ns_pos && navigator.userAgent.indexOf("MSIE 6") != -1), + ie7: (!this.ns_pos && navigator.userAgent.indexOf("MSIE 7") != -1), + ie8: (!this.ns_pos && navigator.userAgent.indexOf("MSIE 8") != -1), + ie9: (!this.ns_pos && navigator.userAgent.indexOf("MSIE 9") != -1), + keyboardless: (this.ipad || this.iphone), + + // are we running as XHTML? (doesn't work on Opera) + is_xhtml: /xml/.test(document.contentType), + + slide_number: 0, // integer slide count: 0, 1, 2, ... + slide_number_element: null, // element containing slide number + slides: [], // set to array of slide div's + notes: [], // set to array of handout div's + backgrounds: [], // set to array of background div's + toolbar: null, // element containing toolbar + title: null, // document title + last_shown: null, // last incrementally shown item + eos: null, // span element for end of slide indicator + toc: null, // table of contents + outline: null, // outline element with the focus + selected_text_len: 0, // length of drag selection on document + view_all: 0, // 1 to view all slides + handouts + want_toolbar: true, // user preference to show/hide toolbar + // NOTE: We would like users to copy paste code from slides + // Allowing click to advance to next slide can be troublesome. + // -- Zilogic Systems + mouse_click_enabled: false, // enables left click for next slide + scroll_hack: 0, // IE work around for position: fixed + disable_slide_click: false, // used by clicked anchors + + lang: "en", // updated to language specified by html file + + help_anchor: null, // used for keyboard focus hack in showToolbar() + help_page: "http://www.w3.org/Talks/Tools/Slidy2/help/help.html", + help_text: "Navigate with mouse click, space bar, Cursor Left/Right, " + + "or Pg Up and Pg Dn. Use S and B to change font size.", + + size_index: 0, + size_adjustment: 0, + sizes: new Array("10pt", "12pt", "14pt", "16pt", "18pt", "20pt", + "22pt", "24pt", "26pt", "28pt", "30pt", "32pt"), + + // needed for efficient resizing + last_width: 0, + last_height: 0, + + + // Needed for cross browser support for relative width/height on + // object elements. The work around is to save width/height attributes + // and then to recompute absolute width/height dimensions on resizing + objects: [], + + // attach initialiation event handlers + set_up: function () { + var init = function() { w3c_slidy.init(); }; + if (typeof window.addEventListener != "undefined") + window.addEventListener("load", init, false); + else + window.attachEvent("onload", init); + }, + + hide_slides: function () { + if (document.body && !w3c_slidy.initialized) + document.body.style.visibility = "hidden"; + else + setTimeout(w3c_slidy.hide_slides, 50); + }, + + // hack to persuade IE to compute correct document height + // as needed for simulating fixed positioning of toolbar + ie_hack: function () { + window.resizeBy(0,-1); + window.resizeBy(0, 1); + }, + + init: function () { + //alert("slidy starting test 10"); + document.body.style.visibility = "visible"; + w3c_slidy_i18n.init(); + this.add_toolbar(); + this.wrap_implicit_slides(); + this.collect_slides(); + this.collect_notes(); + this.collect_backgrounds(); + this.objects = document.body.getElementsByTagName("object"); + this.patch_anchors(); + this.slide_number = this.find_slide_number(location.href); + window.offscreenbuffering = true; + this.size_adjustment = this.find_size_adjust(); + this.time_left = this.find_duration(); + this.hide_image_toolbar(); // suppress IE image toolbar popup + this.init_outliner(); // activate fold/unfold support + this.title = document.title; + + // work around for opera bug + this.is_xhtml = (document.body.tagName == "BODY" ? false : true); + + if (this.slides.length > 0) + { + var slide = this.slides[this.slide_number]; + + if (this.slide_number > 0) + { + this.set_visibility_all_incremental("visible"); + this.last_shown = this.previous_incremental_item(null); + this.set_eos_status(true); + } + else + { + this.last_shown = null; + this.set_visibility_all_incremental("hidden"); + this.set_eos_status(!this.next_incremental_item(this.last_shown)); + } + + this.set_location(); + this.add_class(this.slides[0], "first-slide"); + w3c_slidy.show_slide(slide); + } + + this.toc = this.table_of_contents(); + + this.add_initial_prompt(); + + // bind event handlers without interfering with custom page scripts + // Tap events behave too weirdly to support clicks reliably on + // iPhone and iPad, so exclude these from click handler + + if (!this.keyboardless) + this.add_listener(document.body, "click", this.mouse_button_click); + + this.add_listener(document, "keydown", this.key_down); + this.add_listener(document, "keypress", this.key_press); + this.add_listener(window, "resize", this.resized); + this.add_listener(window, "scroll", this.scrolled); + this.add_listener(window, "unload", this.unloaded); + + if (!document.body.onclick) + document.body.onclick = function () { }; + + this.single_slide_view(); + + //this.set_location(); + + this.resized(); + + if (this.ie7) + setTimeout(w3c_slidy.ie_hack, 100); + + this.show_toolbar(); + + // for back button detection + setInterval(function () { w3c_slidy.check_location(); }, 200); + w3c_slidy.initialized = true; + }, + + // create div element with links to each slide + table_of_contents: function () { + var toc = this.create_element("div"); + this.add_class(toc, "slidy_toc hidden"); + //toc.setAttribute("tabindex", "0"); + + var heading = this.create_element("div"); + this.add_class(heading, "toc-heading"); + heading.innerHTML = "Table of Contents".localize(); + + toc.appendChild(heading); + var previous = null; + + for (var i = 0; i < this.slides.length; ++i) + { + var title = this.has_class(this.slides[i], "title"); + var num = document.createTextNode((i + 1) + ". "); + + toc.appendChild(num); + + var a = this.create_element("a"); + a.setAttribute("href", "#(" + (i+1) + ")"); + + if (title) + this.add_class(a, "titleslide"); + + var name = document.createTextNode(this.slide_name(i)); + a.appendChild(name); + a.onclick = w3c_slidy.toc_click; + a.onkeydown = w3c_slidy.toc_keydown; + a.previous = previous; + + if (previous) + previous.next = a; + + toc.appendChild(a); + + if (i == 0) + toc.first = a; + + if (i < this.slides.length - 1) + { + var br = this.create_element("br"); + toc.appendChild(br); + } + + previous = a; + } + + toc.focus = function () { + if (this.first) + this.first.focus(); + } + + toc.onmouseup = w3c_slidy.mouse_button_up; + + toc.onclick = function (e) { + e||(e=window.event); + + if (w3c_slidy.selected_text_len <= 0) + w3c_slidy.hide_table_of_contents(); + + w3c_slidy.stop_propagation(e); + + if (e.cancel != undefined) + e.cancel = true; + + if (e.returnValue != undefined) + e.returnValue = false; + + return false; + }; + + document.body.insertBefore(toc, document.body.firstChild); + return toc; + }, + + is_shown_toc: function () { + return !w3c_slidy.has_class(w3c_slidy.toc, "hidden"); + }, + + show_table_of_contents: function () { + w3c_slidy.remove_class(w3c_slidy.toc, "hidden"); + var toc = w3c_slidy.toc; + toc.focus(); + + if (w3c_slidy.ie7 && w3c_slidy.slide_number == 0) + setTimeout(w3c_slidy.ie_hack, 100); + }, + + hide_table_of_contents: function () { + w3c_slidy.add_class(w3c_slidy.toc, "hidden"); + + if (!w3c_slidy.opera) + w3c_slidy.help_anchor.focus(); + }, + + toggle_table_of_contents: function () { + if (w3c_slidy.is_shown_toc()) + w3c_slidy.hide_table_of_contents(); + else + w3c_slidy.show_table_of_contents(); + }, + + // called on clicking toc entry + toc_click: function (e) { + if (!e) + e = window.event; + + var target = w3c_slidy.get_target(e); + + if (target && target.nodeType == 1) + { + var uri = target.getAttribute("href"); + + if (uri) + { + //alert("going to " + uri); + var slide = w3c_slidy.slides[w3c_slidy.slide_number]; + w3c_slidy.hide_slide(slide); + w3c_slidy.slide_number = w3c_slidy.find_slide_number(uri); + slide = w3c_slidy.slides[w3c_slidy.slide_number]; + w3c_slidy.last_shown = null; + w3c_slidy.set_location(); + w3c_slidy.set_visibility_all_incremental("hidden"); + w3c_slidy.set_eos_status(!w3c_slidy.next_incremental_item(w3c_slidy.last_shown)); + w3c_slidy.show_slide(slide); + //target.focus(); + + try + { + if (!w3c_slidy.opera) + w3c_slidy.help_anchor.focus(); + } + catch (e) + { + } + } + } + + w3c_slidy.hide_table_of_contents(e); + if (w3c_slidy.ie7) w3c_slidy.ie_hack(); + w3c_slidy.stop_propagation(e); + return w3c_slidy.cancel(e); + }, + + // called onkeydown for toc entry + toc_keydown: function (event) { + var key; + + if (!event) + var event = window.event; + + // kludge around NS/IE differences + if (window.event) + key = window.event.keyCode; + else if (event.which) + key = event.which; + else + return true; // Yikes! unknown browser + + // ignore event if key value is zero + // as for alt on Opera and Konqueror + if (!key) + return true; + + // check for concurrent control/command/alt key + // but are these only present on mouse events? + + if (event.ctrlKey || event.altKey) + return true; + + if (key == 13) + { + var uri = this.getAttribute("href"); + + if (uri) + { + //alert("going to " + uri); + var slide = w3c_slidy.slides[w3c_slidy.slide_number]; + w3c_slidy.hide_slide(slide); + w3c_slidy.slide_number = w3c_slidy.find_slide_number(uri); + slide = w3c_slidy.slides[w3c_slidy.slide_number]; + w3c_slidy.last_shown = null; + w3c_slidy.set_location(); + w3c_slidy.set_visibility_all_incremental("hidden"); + w3c_slidy.set_eos_status(!w3c_slidy.next_incremental_item(w3c_slidy.last_shown)); + w3c_slidy.show_slide(slide); + //target.focus(); + + try + { + if (!w3c_slidy.opera) + w3c_slidy.help_anchor.focus(); + } + catch (e) + { + } + } + + w3c_slidy.hide_table_of_contents(); + + if (self.ie7) + w3c_slidy.ie_hack(); + + return w3c_slidy.cancel(event); + } + + if (key == 40 && this.next) + { + this.next.focus(); + return w3c_slidy.cancel(event); + } + + if (key == 38 && this.previous) + { + this.previous.focus(); + return w3c_slidy.cancel(event); + } + + return true; + }, + + + // ### OBSOLETE ### + before_print: function () { + this.show_all_slides(); + this.hide_toolbar(); + alert("before print"); + }, + + // ### OBSOLETE ### + after_print: function () { + if (!this.view_all) + { + this.single_slide_view(); + this.show_toolbar(); + } + alert("after print"); + }, + + // ### OBSOLETE ### + print_slides: function () { + this.before_print(); + window.print(); + this.after_print(); + }, + + // ### OBSOLETE ?? ### + toggle_view: function () { + if (this.view_all) + { + this.single_slide_view(); + this.show_toolbar(); + this.view_all = 0; + } + else + { + this.show_all_slides(); + this.hide_toolbar(); + this.view_all = 1; + } + }, + + // prepare for printing ### OBSOLETE ### + show_all_slides: function () { + this.remove_class(document.body, "single_slide"); + this.set_visibility_all_incremental("visible"); + }, + + // restore after printing ### OBSOLETE ### + single_slide_view: function () { + this.add_class(document.body, "single_slide"); + this.set_visibility_all_incremental("visible"); + this.last_shown = this.previous_incremental_item(null); + }, + + // suppress IE's image toolbar pop up + hide_image_toolbar: function () { + if (!this.ns_pos) + { + var images = document.getElementsByTagName("IMG"); + + for (var i = 0; i < images.length; ++i) + images[i].setAttribute("galleryimg", "no"); + } + }, + + unloaded: function (e) { + //alert("unloaded"); + }, + + // Safari and Konqueror don't yet support getComputedStyle() + // and they always reload page when location.href is updated + is_KHTML: function () { + var agent = navigator.userAgent; + return (agent.indexOf("KHTML") >= 0 ? true : false); + }, + + // find slide name from first h1 element + // default to document title + slide number + slide_name: function (index) { + var name = null; + var slide = this.slides[index]; + + var heading = this.find_heading(slide); + + if (heading) + name = this.extract_text(heading); + + if (!name) + name = this.title + "(" + (index + 1) + ")"; + + name.replace(/\&/g, "&"); + name.replace(/\/g, ">"); + + return name; + }, + + // find first h1 element in DOM tree + find_heading: function (node) { + if (!node || node.nodeType != 1) + return null; + + if (node.nodeName == "H1" || node.nodeName == "h1") + return node; + + var child = node.firstChild; + + while (child) + { + node = this.find_heading(child); + + if (node) + return node; + + child = child.nextSibling; + } + + return null; + }, + + // recursively extract text from DOM tree + extract_text: function (node) { + if (!node) + return ""; + + // text nodes + if (node.nodeType == 3) + return node.nodeValue; + + // elements + if (node.nodeType == 1) + { + node = node.firstChild; + var text = ""; + + while (node) + { + text = text + this.extract_text(node); + node = node.nextSibling; + } + + return text; + } + + return ""; + }, + + // find copyright text from meta element + find_copyright: function () { + var name, content; + var meta = document.getElementsByTagName("meta"); + + for (var i = 0; i < meta.length; ++i) + { + name = meta[i].getAttribute("name"); + content = meta[i].getAttribute("content"); + + if (name == "copyright") + return content; + } + + return null; + }, + + find_size_adjust: function () { + var name, content, offset; + var meta = document.getElementsByTagName("meta"); + + for (var i = 0; i < meta.length; ++i) + { + name = meta[i].getAttribute("name"); + content = meta[i].getAttribute("content"); + + if (name == "font-size-adjustment") + return 1 * content; + } + + return 1; + }, + + // for 20 minutes + find_duration: function () { + var name, content, offset; + var meta = document.getElementsByTagName("meta"); + + for (var i = 0; i < meta.length; ++i) + { + name = meta[i].getAttribute("name"); + content = meta[i].getAttribute("content"); + + if (name == "duration") + return 60000 * content; + } + + return null; + }, + + replace_by_non_breaking_space: function (str) { + for (var i = 0; i < str.length; ++i) + str[i] = 160; + }, + + // ### CHECK ME ### is use of "li" okay for text/html? + // for XHTML do we also need to specify namespace? + init_outliner: function () { + var items = document.getElementsByTagName("li"); + + for (var i = 0; i < items.length; ++i) + { + var target = items[i]; + + if (!this.has_class(target.parentNode, "outline")) + continue; + + target.onclick = this.outline_click; +/* ### more work needed for IE6 + if (!this.ns_pos) + { + target.onmouseover = this.hover_outline; + target.onmouseout = this.unhover_outline; + } +*/ + if (this.foldable(target)) + { + target.foldable = true; + target.onfocus = function () {w3c_slidy.outline = this;}; + target.onblur = function () {w3c_slidy.outline = null;}; + + if (!target.getAttribute("tabindex")) + target.setAttribute("tabindex", "0"); + + if (this.has_class(target, "expand")) + this.unfold(target); + else + this.fold(target); + } + else + { + this.add_class(target, "nofold"); + target.visible = true; + target.foldable = false; + } + } + }, + + foldable: function (item) { + if (!item || item.nodeType != 1) + return false; + + var node = item.firstChild; + + while (node) + { + if (node.nodeType == 1 && this.is_block(node)) + return true; + + node = node.nextSibling; + } + + return false; + }, + + // ### CHECK ME ### switch to add/remove "hidden" class + fold: function (item) { + if (item) + { + this.remove_class(item, "unfolded"); + this.add_class(item, "folded"); + } + + var node = item ? item.firstChild : null; + + while (node) + { + if (node.nodeType == 1 && this.is_block(node)) // element + { + w3c_slidy.add_class(node, "hidden"); + } + + node = node.nextSibling; + } + + item.visible = false; + }, + + // ### CHECK ME ### switch to add/remove "hidden" class + unfold: function (item) { + if (item) + { + this.add_class(item, "unfolded"); + this.remove_class(item, "folded"); + } + + var node = item ? item.firstChild : null; + + while (node) + { + if (node.nodeType == 1 && this.is_block(node)) // element + { + w3c_slidy.remove_class(node, "hidden"); + } + + node = node.nextSibling; + } + + item.visible = true; + }, + + outline_click: function (e) { + if (!e) + e = window.event; + + var rightclick = false; + var target = w3c_slidy.get_target(e); + + while (target && target.visible == undefined) + target = target.parentNode; + + if (!target) + return true; + + if (e.which) + rightclick = (e.which == 3); + else if (e.button) + rightclick = (e.button == 2); + + if (!rightclick && target.visible != undefined) + { + if (target.foldable) + { + if (target.visible) + w3c_slidy.fold(target); + else + w3c_slidy.unfold(target); + } + + w3c_slidy.stop_propagation(e); + e.cancel = true; + e.returnValue = false; + } + + return false; + }, + + add_initial_prompt: function () { + var prompt = this.create_element("div"); + prompt.setAttribute("class", "initial_prompt"); + + var p1 = this.create_element("p"); + prompt.appendChild(p1); + p1.setAttribute("class", "help"); + + if (this.keyboardless) + p1.innerHTML = "Tap footer to move to next slide"; + else + p1.innerHTML = "Space or Right Arrow to move to next " + + "slide, click help below for more details"; + + this.add_listener(prompt, "click", function (e) { + document.body.removeChild(prompt); + w3c_slidy.stop_propagation(e); + + if (e.cancel != undefined) + e.cancel = true; + + if (e.returnValue != undefined) + e.returnValue = false; + + return false; + }); + + document.body.appendChild(prompt); + this.initial_prompt = prompt; + setTimeout(function() {document.body.removeChild(prompt);}, 5000); + }, + + add_toolbar: function () { + var counter, page; + + this.toolbar = this.create_element("div"); + this.toolbar.setAttribute("class", "toolbar"); + + // a reasonably behaved browser + if (this.ns_pos || !this.ie6) + { + var right = this.create_element("div"); + right.setAttribute("style", "float: right; text-align: right"); + + counter = this.create_element("span") + counter.innerHTML = "slide".localize() + " n/m"; + right.appendChild(counter); + this.toolbar.appendChild(right); + + var left = this.create_element("div"); + left.setAttribute("style", "text-align: left"); + + // global end of slide indicator + this.eos = this.create_element("span"); + this.eos.innerHTML = "* "; + left.appendChild(this.eos); + + var help = this.create_element("a"); + help.setAttribute("href", this.help_page); + help.setAttribute("title", this.help_text.localize()); + help.innerHTML = "help?".localize(); + left.appendChild(help); + this.help_anchor = help; // save for focus hack + + var gap1 = document.createTextNode(" "); + left.appendChild(gap1); + + var contents = this.create_element("a"); + contents.setAttribute("href", "javascript:w3c_slidy.toggle_table_of_contents()"); + contents.setAttribute("title", "table of contents".localize()); + contents.innerHTML = "contents?".localize(); + left.appendChild(contents); + + var gap2 = document.createTextNode(" "); + left.appendChild(gap2); + + var copyright = this.find_copyright(); + + if (copyright) + { + var span = this.create_element("span"); + span.className = "copyright"; + span.innerHTML = copyright; + left.appendChild(span); + } + + this.toolbar.setAttribute("tabindex", "0"); + this.toolbar.appendChild(left); + } + else // IE6 so need to work around its poor CSS support + { + this.toolbar.style.position = (this.ie7 ? "fixed" : "absolute"); + this.toolbar.style.zIndex = "200"; + this.toolbar.style.width = "99.9%"; + this.toolbar.style.height = "1.2em"; + this.toolbar.style.top = "auto"; + this.toolbar.style.bottom = "0"; + this.toolbar.style.left = "0"; + this.toolbar.style.right = "0"; + this.toolbar.style.textAlign = "left"; + this.toolbar.style.fontSize = "60%"; + this.toolbar.style.color = "red"; + this.toolbar.borderWidth = 0; + this.toolbar.className = "toolbar"; + this.toolbar.style.background = "rgb(240,240,240)"; + + // would like to have help text left aligned + // and page counter right aligned, floating + // div's don't work, so instead use nested + // absolutely positioned div's. + + var sp = this.create_element("span"); + sp.innerHTML = "  * "; + this.toolbar.appendChild(sp); + this.eos = sp; // end of slide indicator + + var help = this.create_element("a"); + help.setAttribute("href", this.help_page); + help.setAttribute("title", this.help_text.localize()); + help.innerHTML = "help?".localize(); + this.toolbar.appendChild(help); + this.help_anchor = help; // save for focus hack + + var gap1 = document.createTextNode(" "); + this.toolbar.appendChild(gap1); + + var contents = this.create_element("a"); + contents.setAttribute("href", "javascript:toggleTableOfContents()"); + contents.setAttribute("title", "table of contents".localize()); + contents.innerHTML = "contents?".localize(); + this.toolbar.appendChild(contents); + + var gap2 = document.createTextNode(" "); + this.toolbar.appendChild(gap2); + + var copyright = this.find_copyright(); + + if (copyright) + { + var span = this.create_element("span"); + span.innerHTML = copyright; + span.style.color = "black"; + span.style.marginLeft = "0.5em"; + this.toolbar.appendChild(span); + } + + counter = this.create_element("div") + counter.style.position = "absolute"; + counter.style.width = "auto"; //"20%"; + counter.style.height = "1.2em"; + counter.style.top = "auto"; + counter.style.bottom = 0; + counter.style.right = "0"; + counter.style.textAlign = "right"; + counter.style.color = "red"; + counter.style.background = "rgb(240,240,240)"; + + counter.innerHTML = "slide".localize() + " n/m"; + this.toolbar.appendChild(counter); + } + + // ensure that click isn't passed through to the page + this.toolbar.onclick = + function (e) { + if (!e) + e = window.event; + + var target = e.target; + + if (!target && e.srcElement) + target = e.srcElement; + + // work around Safari bug + if (target && target.nodeType == 3) + target = target.parentNode; + + w3c_slidy.stop_propagation(e); + + if (target && target.nodeName.toLowerCase() != "a") + w3c_slidy.mouse_button_click(e); + }; + + this.slide_number_element = counter; + this.set_eos_status(false); + document.body.appendChild(this.toolbar); + }, + + // wysiwyg editors make it hard to use div elements + // e.g. amaya loses the div when you copy and paste + // this function wraps div elements around implicit + // slides which start with an h1 element and continue + // up to the next heading or div element + wrap_implicit_slides: function () { + var i, heading, node, next, div; + var headings = document.getElementsByTagName("h1"); + + if (!headings) + return; + + for (i = 0; i < headings.length; ++i) + { + heading = headings[i]; + + if (heading.parentNode != document.body) + continue; + + node = heading.nextSibling; + + div = document.createElement("div"); + this.add_class(div, "slide"); + document.body.replaceChild(div, heading); + div.appendChild(heading); + + while (node) + { + if (node.nodeType == 1 && // an element + (node.nodeName == "H1" || + node.nodeName == "h1" || + node.nodeName == "DIV" || + node.nodeName == "div")) + break; + + next = node.nextSibling; + node = document.body.removeChild(node); + div.appendChild(node); + node = next; + } + } + }, + +// return new array of all slides + collect_slides: function () { + var slides = new Array(); + var divs = document.body.getElementsByTagName("div"); + + for (var i = 0; i < divs.length; ++i) + { + div = divs.item(i); + + if (this.has_class(div, "slide")) + { + // add slide to collection + slides[slides.length] = div; + + // hide each slide as it is found + this.add_class(div, "hidden"); + + // add dummy
at end for scrolling hack + var node1 = document.createElement("br"); + div.appendChild(node1); + var node2 = document.createElement("br"); + div.appendChild(node2); + } + else if (this.has_class(div, "background")) + { // work around for Firefox SVG reload bug + // which otherwise replaces 1st SVG graphic with 2nd + div.style.display = "block"; + } + } + + this.slides = slides; + }, + + // return new array of all
+ collect_notes: function () { + var notes = new Array(); + var divs = document.body.getElementsByTagName("div"); + + for (var i = 0; i < divs.length; ++i) + { + div = divs.item(i); + + if (this.has_class(div, "handout")) + { + // add note to collection + notes[notes.length] = div; + + // and hide it + this.add_class(div, "hidden"); + } + } + + this.notes = notes; + }, + + // return new array of all
+ // including named backgrounds e.g. class="background titlepage" + collect_backgrounds: function () { + var backgrounds = new Array(); + var divs = document.body.getElementsByTagName("div"); + + for (var i = 0; i < divs.length; ++i) + { + div = divs.item(i); + + if (this.has_class(div, "background")) + { + // add background to collection + backgrounds[backgrounds.length] = div; + + // and hide it + this.add_class(div, "hidden"); + } + } + + this.backgrounds = backgrounds; + }, + + // set click handlers on all anchors + patch_anchors: function () { + var self = w3c_slidy; + var handler = function (event) { + // compare this.href with location.href + // for link to another slide in this doc + + if (self.page_address(this.href) == self.page_address(location.href)) + { + // yes, so find new slide number + var newslidenum = self.find_slide_number(this.href); + + if (newslidenum != self.slide_number) + { + var slide = self.slides[self.slide_number]; + self.hide_slide(slide); + self.slide_number = newslidenum; + slide = self.slides[self.slide_number]; + self.show_slide(slide); + self.set_location(); + } + } + else if (this.target == null) + location.href = this.href; + + this.blur(); + self.disable_slide_click = true; + }; + + var anchors = document.body.getElementsByTagName("a"); + + for (var i = 0; i < anchors.length; ++i) + { + if (window.addEventListener) + anchors[i].addEventListener("click", handler, false); + else + anchors[i].attachEvent("onclick", handler); + } + }, + + // ### CHECK ME ### see which functions are invoked via setTimeout + // either directly or indirectly for use of w3c_slidy vs this + show_slide_number: function () { + var timer = w3c_slidy.get_timer(); + w3c_slidy.slide_number_element.innerHTML = timer + "slide".localize() + " " + + (w3c_slidy.slide_number + 1) + "/" + w3c_slidy.slides.length; + }, + + // every 200mS check if the location has been changed as a + // result of the user activating the Back button/menu item + // doesn't work for Opera < 9.5 + check_location: function () { + var hash = location.hash; + + if (w3c_slidy.slide_number > 0 && (hash == "" || hash == "#")) + w3c_slidy.goto_slide(0); + else if (hash.length > 2 && hash != "#("+(w3c_slidy.slide_number+1)+")") + { + var num = parseInt(location.hash.substr(2)); + + if (!isNaN(num)) + w3c_slidy.goto_slide(num-1); + } + + if (w3c_slidy.time_left && w3c_slidy.slide_number > 0) + { + w3c_slidy.show_slide_number(); + + if (w3c_slidy.time_left > 0) + w3c_slidy.time_left -= 200; + } + }, + + get_timer: function () { + var timer = ""; + if (w3c_slidy.time_left) + { + var mins, secs; + secs = Math.floor(w3c_slidy.time_left/1000); + mins = Math.floor(secs / 60); + secs = secs % 60; + timer = (mins ? mins+"m" : "") + secs + "s "; + } + + return timer; + }, + + // this doesn't push location onto history stack for IE + // for which a hidden iframe hack is needed: load page into + // the iframe with script that set's parent's location.hash + // but that won't work for standalone use unless we can + // create the page dynamically via a javascript: URL + set_location: function () { + var uri = w3c_slidy.page_address(location.href); + var hash = "#(" + (w3c_slidy.slide_number+1) + ")"; + + if (w3c_slidy.slide_number >= 0) + uri = uri + hash; + + if (w3c_slidy.ie && !w3c_slidy.ie8) + w3c_slidy.push_hash(hash); + + if (uri != location.href) // && !khtml + location.href = uri; + + if (this.khtml) + hash = "(" + (w3c_slidy.slide_number+1) + ")"; + + if (!this.ie && location.hash != hash && location.hash != "") + location.hash = hash; + + document.title = w3c_slidy.title + " (" + (w3c_slidy.slide_number+1) + ")"; + w3c_slidy.show_slide_number(); + }, + + page_address: function (uri) { + var i = uri.indexOf("#"); + + if (i < 0) + i = uri.indexOf("%23"); + + // check if anchor is entire page + + if (i < 0) + return uri; // yes + + return uri.substr(0, i); + }, + + // only used for IE6 and IE7 + on_frame_loaded: function (hash) { + location.hash = hash; + var uri = w3c_slidy.page_address(location.href); + location.href = uri + hash; + }, + + // history hack with thanks to Bertrand Le Roy + push_hash: function (hash) { + if (hash == "") hash = "#(1)"; + window.location.hash = hash; + + var doc = document.getElementById("historyFrame").contentWindow.document; + doc.open("javascript:''"); + // PWL modified this string literal to break the close script tag + // which otherwise gets parsed when incorporated + doc.write(" + + +endif::linkcss[] +ifndef::linkcss[] + +endif::linkcss[] +endif::disable-javascript[] +ifdef::asciimath[] +ifdef::linkcss[] + +endif::linkcss[] +ifndef::linkcss[] + +endif::linkcss[] +endif::asciimath[] +ifdef::latexmath[] +ifdef::linkcss[] + +endif::linkcss[] +ifndef::linkcss[] + +endif::linkcss[] +endif::latexmath[] +{docinfo1,docinfo2#}{include:{docdir}/docinfo.html} +{docinfo,docinfo2#}{include:{docdir}/{docname}-docinfo.html} +template::[docinfo] + + +# Article, book header. +ifndef::doctype-manpage[] + +endif::doctype-manpage[] +# Man page header. +ifdef::doctype-manpage[] + +endif::doctype-manpage[] +
+ +[footer] +
+{disable-javascript%

} + + + + +ifdef::doctype-manpage[] +[synopsis] +template::[sect1] +endif::doctype-manpage[] + +ifdef::quirks[] +include::xhtml11-quirks.conf[] +endif::quirks[] diff --git a/stylesheets/zslide.conf b/stylesheets/zslide.conf new file mode 100644 index 0000000..bdc3430 --- /dev/null +++ b/stylesheets/zslide.conf @@ -0,0 +1,148 @@ +# +# Asciidoc Configuration file for slidy HTML generation. +# + +include::xhtml11.conf[] + +[literalparagraph] +template::[listingblock] + +[openblock] +
+
{title}
+
+| +
+ +[listtags-bulleted] +list={title?
{title}
}
|
+item=
  • |
  • +text=| + +[listtags-numbered] +# The start attribute is not valid XHTML 1.1 but all browsers support it. +list={title?
    {title}
    }
    | +item=
  • |
  • +text=| + +[listtags-labeled] +list=
    {title?
    {title}
    }
    |
    +entry= +label= +term=
    |
    +item=
    |
    +text=

    |

    + +[preamble] +# Untitled elements between header and first section title. +
    +
    +| +
    +
    + +[sect1] +
    +{numbered?{sectnum} }{title} +# Set max-width here because Slidy ignores max-width on body. +
    +
    +
    +| + +[sect2] +
    +{numbered?{sectnum} }{title} +# Set max-width here because Slidy ignores max-width on body. +
    +| +
    +
    + +[appendix] +
    +{numbered?{sectnum} }{appendix-caption} {counter:appendix-number:A}: {title} +# Set max-width here because Slidy ignores max-width on body. +
    +| +
    +
    + +[header] + + + + +{doctitle=} + +ifndef::copyright[] + + + +ifdef::linkcss[] + + + +ifdef::pygments[] + + +endif::linkcss[] +ifndef::linkcss[] + + +endif::linkcss[] +ifdef::asciimath[] +ifdef::linkcss[] + +endif::linkcss[] +ifndef::linkcss[] + +endif::linkcss[] +endif::asciimath[] +ifdef::latexmath[] +ifdef::linkcss[] + +endif::linkcss[] +ifndef::linkcss[] + +endif::linkcss[] +endif::latexmath[] + + + + +[footer] + +