Add Maple post with mw2txt.py script.
authorW. Trevor King <wking@drexel.edu>
Wed, 22 Feb 2012 20:48:27 +0000 (15:48 -0500)
committerW. Trevor King <wking@drexel.edu>
Wed, 22 Feb 2012 20:48:27 +0000 (15:48 -0500)
posts/Maple.mdwn [new file with mode: 0644]
posts/Maple/example.mw [new file with mode: 0644]
posts/Maple/mw2txt.py [new file with mode: 0755]

diff --git a/posts/Maple.mdwn b/posts/Maple.mdwn
new file mode 100644 (file)
index 0000000..50b3f01
--- /dev/null
@@ -0,0 +1,28 @@
+Some of the classes I TA use [Maple][].  (Caveat: I prefer [[Python]],
+as a more general language.  Use [[SymPy]] or [Sage][] if you need
+symbolic processing.)  Anyhow, I get Maple worksheets to grade.
+[[SSH]]ing into the department computer lab to fire up `xmaple` is a
+pain, so I wrote [[mw2txt.py]] to extract the Maple commands from the
+worksheet.  It benefits from the fact that worksheets are fairly clean
+XML.  Graphs and equations are more difficult, since they have
+complicated layout and are stored as encoded blobs.  Other than that,
+things work pretty well.  Here's the output from my [[example.mw]]
+example worksheet, picking out the math-mode sections (in red) and
+unprocessed blocks (in yellow) from the comments (uncolored).
+
+<pre><code>$ mw2txt.py --color example.mw 
+Hi there
+<span style="color: red">&gt; restart;
+&gt; interface(prettyprint=0):
+&gt; 1;#</span> one  <span style="color: red">+</span> plus <span style="color: red">2</span> two <span style="color: red">;</span>
+1
+<span style="color: red">&gt; 3 + 4;</span>  bold
+7
+<span style="color: yellow">Equation</span>
+</code></pre>
+
+[Maple]: http://www.maplesoft.com/products/maple/
+[Sage]: http://www.sagemath.org/
+
+[[!tag tags/code]]
+[[!tag tags/python]]
diff --git a/posts/Maple/example.mw b/posts/Maple/example.mw
new file mode 100644 (file)
index 0000000..57278d8
--- /dev/null
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Worksheet>
+<Version major="15" minor="0"/>
+<Label-Scheme value="2" prefix=""/>
+<View-Properties presentation="true"></View-Properties>
+<MapleNet-Properties elisiondigitsbefore="100" labelling="true" indentamount="4" elisiontermsthreshold="10000" ansi="false" errorbreak="1" useclientjvm="true" echo="1" imaginaryunit="I" labelwidth="20" contextmenusize="automatic" plotdriver="opengl" elisiondigitsafter="100" plotoutput="terminal" helpbrowser="standard" rtablesize="10" elisiontermsbefore="100" elisiondigitsthreshold="10000" typesetting="standard" plotdevice="inline" verboseproc="1" showassumed="1" errorcursor="false" longdelim="true" plotoptions="" quiet="false" elisiontermsafter="100" screenwidth="79" preplot="" prettyprint="3" displayprecision="-1" screenpixelheight="480" warnlevel="3" screenheight="25" latexwidth="6.0" postplot="" prompt="&gt; " ShowLabels="true"/>
+<Styles><Font name="Ordered List 1" background="[255,255,255]" bold="false" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Annotation Text" background="[255,255,255]" bold="false" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Ordered List 2" background="[255,255,255]" bold="false" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Ordered List 3" background="[255,255,255]" bold="false" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Ordered List 4" background="[255,255,255]" bold="false" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Ordered List 5" background="[255,255,255]" bold="false" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Author" background="[255,255,255]" bold="false" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Annotation Title" background="[255,255,255]" bold="true" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="18" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Warning" background="[255,255,255]" bold="false" executable="false" family="Courier New" foreground="[0,0,255]" italic="false" opaque="false" readonly="true" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Caption Reference" background="[255,255,255]" bold="true" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Maple Input Placeholder" background="[255,255,255]" bold="true" executable="true" family="Courier New" foreground="[200,0,200]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="true"/>
+<Font name="Maple Plot" background="[255,255,255]" bold="false" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Code" background="[255,255,255]" bold="false" executable="false" family="Courier New" foreground="[255,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Line Printed Output" background="[255,255,255]" bold="false" executable="false" family="Courier New" foreground="[0,0,255]" italic="false" opaque="false" readonly="true" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Text Output" background="[255,255,255]" bold="false" executable="false" family="Courier New" foreground="[0,0,255]" italic="false" opaque="false" readonly="true" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Diagnostic" background="[255,255,255]" bold="false" executable="false" family="Courier New" foreground="[40,120,40]" italic="false" opaque="false" readonly="true" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="2D Inert Output" background="[255,255,255]" bold="false" executable="true" family="Times New Roman" foreground="[144,144,144]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Normal" background="[255,255,255]" bold="false" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Hyperlink" background="[255,255,255]" bold="false" executable="false" family="Times New Roma" foreground="[0,128,128]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="true" placeholder="false"/>
+<Font name="Maple Output" background="[255,255,255]" bold="false" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Dash Item" background="[255,255,255]" bold="false" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="2D Math" background="[255,255,255]" bold="false" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Maple Input" background="[255,255,255]" bold="true" executable="true" family="Courier New" foreground="[255,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="2D Output" background="[255,255,255]" bold="false" executable="false" family="Times New Roman" foreground="[0,0,255]" italic="false" opaque="false" readonly="true" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="2D Input" background="[255,255,255]" bold="false" executable="true" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="HyperlinkError" background="[255,255,255]" bold="false" executable="false" family="Courier New" foreground="[255,0,255]" italic="false" opaque="false" readonly="true" size="12" subscript="false" superscript="false" underline="true" placeholder="false"/>
+<Font name="Header and Footer" background="[255,255,255]" bold="false" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="10" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Error" background="[255,255,255]" bold="false" executable="false" family="Courier New" foreground="[255,0,255]" italic="false" opaque="false" readonly="true" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Title" background="[255,255,255]" bold="true" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="18" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Heading 1" background="[255,255,255]" bold="true" executable="false" family="Times New Roma" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="18" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Text" background="[255,255,255]" bold="false" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Bullet Item" background="[255,255,255]" bold="false" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Heading 4" background="[255,255,255]" bold="false" executable="false" family="Times New Roma" foreground="[0,0,0]" italic="true" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Equation Label" background="[255,255,255]" bold="true" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Heading 3" background="[255,255,255]" bold="true" executable="false" family="Times New Roma" foreground="[0,0,0]" italic="true" opaque="false" readonly="false" size="14" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="Heading 2" background="[255,255,255]" bold="true" executable="false" family="Times New Roma" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="16" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="HyperlinkWarning" background="[255,255,255]" bold="false" executable="false" family="Courier New" foreground="[0,0,255]" italic="false" opaque="false" readonly="true" size="12" subscript="false" superscript="false" underline="true" placeholder="false"/>
+<Font name="Dictionary Hyperlink" background="[255,255,255]" bold="false" executable="false" family="Times New Roma" foreground="[147,0,15]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="true" placeholder="false"/>
+<Font name="Caption Text" background="[255,255,255]" bold="true" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Font name="List Item" background="[255,255,255]" bold="false" executable="false" family="Times New Roman" foreground="[0,0,0]" italic="false" opaque="false" readonly="false" size="12" subscript="false" superscript="false" underline="false" placeholder="false"/>
+<Layout name="Ordered List 1" alignment="left" bullet="numeric" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.0" spaceabove="3" spacebelow="3" linebreak="space" pagebreak-before="false" initial="-1" bulletsuffix=""/>
+<Layout name="Ordered List 2" alignment="left" bullet="alphabetic" firstindent="0" leftmargin="36" rightmargin="0" linespacing="0.0" spaceabove="3" spacebelow="3" linebreak="space" pagebreak-before="false" initial="-1" bulletsuffix=""/>
+<Layout name="Ordered List 3" alignment="left" bullet="roman" firstindent="0" leftmargin="72" rightmargin="0" linespacing="0.0" spaceabove="3" spacebelow="3" linebreak="space" pagebreak-before="false" initial="-1" bulletsuffix=""/>
+<Layout name="Ordered List 4" alignment="left" bullet="ALPHABETIC" firstindent="0" leftmargin="108" rightmargin="0" linespacing="0.0" spaceabove="3" spacebelow="3" linebreak="space" pagebreak-before="false" initial="-1" bulletsuffix=""/>
+<Layout name="Ordered List 5" alignment="left" bullet="ROMAN" firstindent="0" leftmargin="144" rightmargin="0" linespacing="0.0" spaceabove="3" spacebelow="3" linebreak="space" pagebreak-before="false" initial="-1" bulletsuffix=""/>
+<Layout name="Author" alignment="centred" bullet="none" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.0" spaceabove="8" spacebelow="8" linebreak="space" pagebreak-before="false" initial="0" bulletsuffix=""/>
+<Layout name="Warning" alignment="left" bullet="none" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.0" spaceabove="0" spacebelow="0" linebreak="space" pagebreak-before="false" initial="0" bulletsuffix=""/>
+<Layout name="Annotation Title" alignment="centred" bullet="none" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.0" spaceabove="12" spacebelow="12" linebreak="space" pagebreak-before="false" initial="0" bulletsuffix=""/>
+<Layout name="Maple Plot" alignment="centred" bullet="none" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.0" spaceabove="0" spacebelow="0" linebreak="space" pagebreak-before="false" initial="0" bulletsuffix=""/>
+<Layout name="Line Printed Output" alignment="left" bullet="none" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.0" spaceabove="0" spacebelow="0" linebreak="any" pagebreak-before="false" initial="0" bulletsuffix=""/>
+<Layout name="Text Output" alignment="left" bullet="none" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.0" spaceabove="0" spacebelow="0" linebreak="newline" pagebreak-before="false" initial="0" bulletsuffix=""/>
+<Layout name="Diagnostic" alignment="left" bullet="none" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.0" spaceabove="0" spacebelow="0" linebreak="any" pagebreak-before="false" initial="0" bulletsuffix=""/>
+<Layout name="Normal" alignment="left" bullet="none" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.0" spaceabove="0" spacebelow="0" linebreak="space" pagebreak-before="false" initial="0" bulletsuffix=""/>
+<Layout name="Maple Output" alignment="centred" bullet="none" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.3" spaceabove="0" spacebelow="0" linebreak="space" pagebreak-before="false" initial="0" bulletsuffix=""/>
+<Layout name="Dash Item" alignment="left" bullet="dash" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.0" spaceabove="3" spacebelow="3" linebreak="space" pagebreak-before="false" initial="0" bulletsuffix=""/>
+<Layout name="HyperlinkError" alignment="left" bullet="none" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.0" spaceabove="0" spacebelow="0" linebreak="space" pagebreak-before="false" initial="0" bulletsuffix=""/>
+<Layout name="Error" alignment="left" bullet="none" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.0" spaceabove="0" spacebelow="0" linebreak="space" pagebreak-before="false" initial="0" bulletsuffix=""/>
+<Layout name="Title" alignment="centred" bullet="none" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.0" spaceabove="12" spacebelow="12" linebreak="space" pagebreak-before="false" initial="0" bulletsuffix=""/>
+<Layout name="Heading 1" alignment="left" bullet="none" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.0" spaceabove="8" spacebelow="4" linebreak="space" pagebreak-before="false" initial="0" bulletsuffix=""/>
+<Layout name="Bullet Item" alignment="left" bullet="dot" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.0" spaceabove="3" spacebelow="3" linebreak="space" pagebreak-before="false" initial="0" bulletsuffix=""/>
+<Layout name="Heading 4" alignment="left" bullet="none" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.0" spaceabove="0" spacebelow="0" linebreak="space" pagebreak-before="false" initial="0" bulletsuffix=""/>
+<Layout name="Heading 3" alignment="left" bullet="none" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.0" spaceabove="0" spacebelow="0" linebreak="space" pagebreak-before="false" initial="0" bulletsuffix=""/>
+<Layout name="Heading 2" alignment="left" bullet="none" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.0" spaceabove="8" spacebelow="2" linebreak="space" pagebreak-before="false" initial="0" bulletsuffix=""/>
+<Layout name="HyperlinkWarning" alignment="left" bullet="none" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.0" spaceabove="0" spacebelow="0" linebreak="space" pagebreak-before="false" initial="0" bulletsuffix=""/>
+<Layout name="List Item" alignment="left" bullet="indent" firstindent="0" leftmargin="0" rightmargin="0" linespacing="0.0" spaceabove="3" spacebelow="3" linebreak="space" pagebreak-before="false" initial="0" bulletsuffix=""/>
+<Pencil-style name="Pencil 5" pen-color="[255,0,0]" pen-height="5.0" pen-width="5.0" pen-opacity="1.0"/>
+<Pencil-style name="Pencil 4" pen-color="[0,0,255]" pen-height="3.0" pen-width="3.0" pen-opacity="1.0"/>
+<Pencil-style name="Pencil 3" pen-color="[0,0,0]" pen-height="3.0" pen-width="3.0" pen-opacity="1.0"/>
+<Pencil-style name="Pencil 2" pen-color="[0,0,255]" pen-height="1.0" pen-width="1.0" pen-opacity="1.0"/>
+<Pencil-style name="Pencil 1" pen-color="[0,0,0]" pen-height="1.0" pen-width="1.0" pen-opacity="1.0"/>
+<Highlighter-style name="Highlighter 2" pen-color="[255,204,0]" pen-height="14.0" pen-width="14.0" pen-opacity="0.8"/>
+<Highlighter-style name="Highlighter 1" pen-color="[255,153,255]" pen-height="12.0" pen-width="8.0" pen-opacity="0.8"/>
+<Highlighter-style name="Highlighter 4" pen-color="[0,255,255]" pen-height="32.0" pen-width="32.0" pen-opacity="0.8"/>
+<Highlighter-style name="Highlighter 3" pen-color="[51,255,0]" pen-height="24.0" pen-width="24.0" pen-opacity="0.8"/>
+<Highlighter-style name="Highlighter 5" pen-color="[255,255,0]" pen-height="48.0" pen-width="48.0" pen-opacity="0.8"/>
+</Styles>
+<Task-table>
+    <Task-category name="&lt;default&gt;">
+    </Task-category>
+</Task-table>
+<Task>
+</Task><Presentation-Block>
+<Group view="presentation" hide-input="false" hide-output="true" inline-output="false" labelreference="L1" drawlabel="true">
+<Input>
+<Text-field style="Text" layout="Normal" alignment="centred">Hi there</Text-field>
+</Input>
+</Group></Presentation-Block><Presentation-Block>
+<Group view="presentation" hide-input="false" hide-output="true" inline-output="false" labelreference="L2" drawlabel="true">
+<Input>
+<Text-field style="Text" layout="Normal"></Text-field>
+</Input>
+</Group>
+<Group view="code" labelreference="L6" drawlabel="true">
+<Input>
+<Text-field prompt="&gt; " style="Maple Input" layout="Normal">restart;</Text-field>
+</Input>
+</Group>
+<Group view="code" labelreference="L7" drawlabel="true">
+<Input>
+<Text-field prompt="&gt; " style="Maple Input" layout="Normal">interface(prettyprint=0):</Text-field>
+</Input>
+</Group>
+<Group view="code" labelreference="L3" drawlabel="true">
+<Input>
+<Text-field prompt="&gt; " style="Maple Input" layout="Normal">1;# <Font style="Text">one  </Font><Font executable="false">+ </Font><Font style="Text">plus </Font><Font executable="false">2 </Font><Font style="Text">two</Font><Font executable="false"> ;</Font></Text-field>
+</Input>
+<Output>
+<Text-field style="Line Printed Output" layout="Line Printed Output">1</Text-field>
+</Output>
+</Group>
+<Group view="code" labelreference="L5" drawlabel="true">
+<Input>
+<Text-field prompt="&gt; " style="Maple Input" layout="Normal">3 + <Font italic="true">4</Font>;<Font bold="true" style="Text">  bold</Font></Text-field>
+</Input>
+<Output>
+<Text-field style="Line Printed Output" layout="Line Printed Output">7</Text-field>
+</Output>
+</Group></Presentation-Block><Presentation-Block>
+<Group view="presentation" hide-input="false" hide-output="true" inline-output="false" labelreference="L4" drawlabel="true">
+<Input>
+<Text-field style="Text" layout="Normal"><Equation executable="false" style="2D Math" input-equation="" display="LUklbXJvd0c2Iy9JK21vZHVsZW5hbWVHNiJJLFR5cGVzZXR0aW5nR0koX3N5c2xpYkdGJzYkLUkjbWlHRiQ2I1EhRicvJSxtYXRodmFyaWFudEdRJ25vcm1hbEYn">JSFH</Equation></Text-field>
+</Input>
+</Group></Presentation-Block>
+</Worksheet>
\ No newline at end of file
diff --git a/posts/Maple/mw2txt.py b/posts/Maple/mw2txt.py
new file mode 100755 (executable)
index 0000000..c19c3fe
--- /dev/null
@@ -0,0 +1,236 @@
+#!/usr/bin/env python
+# 
+# Copyright (C) 2011-2012 W. Trevor King <wking@drexel.edu>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation, either version 3 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program.  If not, see
+# <http://www.gnu.org/licenses/>.
+
+"""View Maple worksheets (.mw) from the command line (without X).
+
+./mw2txt.py -c input.mw | less
+./mw2txt.py -m input.mw | /opt/maple15/bin/maple | less
+"""
+
+import sys as _sys
+
+import lxml.etree as _lxml_etree
+
+try:
+    from pygments.console import colorize as _colorize
+except ImportError, e:
+    _sys.stderr.write(str(e) + '\n')
+    def _write_color(string, color=None, stream=None):
+        if stream is None:
+            stream = _sys.stdout
+        stream.write(string)
+else:
+    def _write_color(string, color=None, stream=None):
+        if color is None:
+            color = 'reset'
+        if stream is None:
+            stream = _sys.stdout
+        stream.write(_colorize(color_key=color, text=string))
+
+
+__version__ = '0.1'
+
+
+class Writer (object):
+    def __init__(self, color=None, stream=None, use_color=False):
+        self.color = color
+        self.stream = stream
+        self.use_color = use_color
+        self.last_char = None
+
+    def __call__(self, text, color=None):
+        if not self.use_color:
+            color = None
+        elif color is None:
+            color = self.color
+        if text == '\n' and self.last_char == '\n':
+            return  # don't add lots of blank lines
+        _write_color(string=text, color=color, stream=self.stream)
+        self.last_char = text[-1]
+
+
+def mw2txt(path, writer, filter_math=False):
+    xml = _lxml_etree.parse(path)
+    pruned_iteration(
+        root=xml.getroot(),
+        match=lambda node: node.tag == 'Text-field',
+        match_action=lambda node: top_text_node2txt(
+            node=node, writer=writer, filter_math=filter_math),
+        match_tail=lambda node:writer(text='\n'))
+
+def top_text_node2txt(node, writer, filter_math=False):
+    if filter_math:
+        match_action = None
+    else:
+        match_action = lambda node: other_in_text_node2txt(
+            node=node, writer=writer)
+    pruned_iteration(
+        root=node,
+        match=lambda node: node.tag not in ['Text-field', 'Font', 'Hyperlink'],
+        match_action=match_action,
+        other_action=lambda node: text_node2txt(
+            node=node, writer=writer, filter_math=filter_math),
+        match_tail=lambda node:tail_node2txt(
+            node=node, writer=writer, filter_math=filter_math),
+        other_tail=lambda node:tail_node2txt(
+            node=node, writer=writer, filter_math=filter_math))
+
+def other_in_text_node2txt(node, writer):
+    if node.tag in ['Drawing-Root']:
+        # ignore missing content
+        pass
+    elif node.tag in ['Equation', 'Image', 'Plot']:
+        # warn about missing content
+        writer(text=node.tag, color='yellow')
+    else:
+        # warn about wierd tag
+        writer(text=node.tag, color='magenta')
+
+def text_node2txt(node, writer, filter_math=False):
+    if node.tag not in ['Text-field', 'Font', 'Hyperlink'] and not filter_math:
+        # warn about wierd tag
+        writer(text=node.tag, color='magenta')
+    write_text(
+        node=node, text=node.text, writer=writer, filter_math=filter_math)
+
+def tail_node2txt(node, writer, filter_math=False):
+    if node.tag != 'Text-field':
+        write_text(
+            node=node.getparent(), text=node.tail, writer=writer,
+            filter_math=filter_math)
+
+def write_text(node, text, writer, filter_math=False):
+    if not text:
+        return
+    style = node_style(node)
+    if filter_math:
+        if style == 'Maple Input':
+            writer(text=text)
+        return
+    prompt = node.get('prompt', None)
+    if prompt:
+        t = '\n'.join(prompt+line for line in text.splitlines())
+        if text.endswith('\n'):
+            t += '\n'  # '\n'.join('a\nb\n'.splitlines()) == 'a\nb'
+        if writer.last_char not in [None, '\n']:
+            t = t[len(prompt):]  # no initial prompt
+        text = t
+    if style == 'Maple Input':
+        color = 'red'
+    else:
+        color = None
+    writer(text=text, color=color)
+
+def node_style(node):
+    p = node
+    while p is not None:
+        style = p.get('style', None)
+        if style:
+            return style
+        p = p.getparent()
+    return None
+
+def pruned_iteration(root, match, match_action=None, match_tail=None,
+                     other_action=None, other_tail=None, debug=False):
+    if debug:
+        _write_color('start pruned iteration from %s\n' % root, color='blue')
+    line = [None]
+    stack = [root]
+    while len(stack) > 0:
+        node = stack.pop(0)
+        p = node.getparent()
+        while line[-1] != p:
+            n = line.pop()
+            if n is None:
+                break
+            _pruned_iteration_handle_tail(
+                node=n, match=match, match_tail=match_tail,
+                other_tail=other_tail, debug=debug)
+        line.append(node)
+        if debug:
+            color_node(node, color='cyan')
+        if match(node):
+            if match_action:
+                match_action(node)
+        else:
+            if other_action:
+                other_action(node)
+            stack = list(node.getchildren()) + stack
+    while len(line) > 0:
+        n = line.pop()
+        if n is None:
+            break
+        _pruned_iteration_handle_tail(
+            node=n, match=match, match_tail=match_tail, other_tail=other_tail,
+            debug=debug)
+    if debug:
+        _write_color('end pruned iteration from %s\n' % root, color='blue')
+
+def _pruned_iteration_handle_tail(node, match, match_tail, other_tail,
+                                  debug=False):
+    if debug:
+        color_node(node, color='magenta', tail=True)
+    if match(node):
+        if match_tail:
+            match_tail(node)
+    else:
+        if other_tail:
+            other_tail(node)
+
+def node_depth(node):
+    depth = 0
+    p = node.getparent()
+    while p is not None:
+        depth += 1
+        p = p.getparent()
+    return depth
+
+def color_node(node, color=None, tail=False):
+    depth = node_depth(node)
+    string = ' '*depth + node.tag
+    if tail:
+        string += ' tail'
+    _write_color(string + '\n', color)
+
+
+if __name__ == '__main__':
+    from optparse import OptionParser as _OptionParser
+
+    # don't wrap epilog paragraphs
+    class OptionParser (_OptionParser):
+        def format_epilog(self, formatter):
+            return self.epilog
+
+    parser = OptionParser(
+        usage='%prog [options] input.mw', epilog='\n'+__doc__)
+    parser.add_option(
+        '-c', '--color', dest='color', action='store_true',
+        help='Use ANSI escape sequences to color output')
+    parser.add_option(
+        '-m', '--maple', dest='maple', action='store_true',
+        help='output text suitable for piping into `maple`')
+
+    options,args = parser.parse_args()
+    path = args[0]
+
+    filter_math = options.maple
+    writer = Writer(use_color=options.color)
+    if options.maple:
+        if options.color:
+            raise ValueError("maple doesn't understand ANSI color")
+    mw2txt(path=path, writer=writer, filter_math=filter_math)