<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="index.xsl"?>
<!-- the xmlns:xhtml attribute is necessary to allow embedded XHTML within
     the XML text sections; each XHTML tag must be prefixed with 'xhtml:' -->
<root>

<header>
  Here's some of the stuff I've done or am working on - Victor Dods - last updated 2022.09.23
</header>

<footer>
  Contact: victor dot dods atsign gmail dot com
</footer>

<categories xmlns:xhtml="http://www.w3.org/1999/xhtml">
  <category>
    <title>Current and theoretically-still-active software projects</title>
    <subcategories>
      <subcategory>
        <name>SEPT (Structured Expression Project Thesis/Toolkit)</name>
        <short-description></short-description>
        <years>2020-</years>
        <description>
          <xhtml:p>
          In 2020 I had put up a new website which I intended to use to publish ideas, and the first article I wrote was
          <xhtml:a href='https://itdont.work/2020/06/29/structured-expression-project-thesis-1-0/'>SEPT (Structured Expression Project Thesis)</xhtml:a>
          and it was a doozy.  I had always been frustrated with the limited expressability in our conventional communication media,
          and wanted to explore methods of expressing information which naturally reflect the rich structure inherent in that information.
          What resulted was a kind of an experimental form factor for an article using, among other structures, a "level of detail"
          structure in which the reader can expand/collapse the article to find greater or less detail as desired.  The thing took
          a month to put together, but I believe that with appropriate tools, this format could be had for free when one composes
          a document in a particular structured way, and furthermore the view of that document could be dynamically modified to
          see the relevant aspects of the information and discard irrelevant aspects.
          </xhtml:p>
          <xhtml:p>
          The exploration of the ideas in SEPT (the thesis) was the direct inspiration for creating SEPT (the SDK).  First was the
          <xhtml:a href='https://github.com/vdods/sept'>SEPT C++ SDK</xhtml:a>, then later the
          <xhtml:a href='https://github.com/vdods/sept-rs'>Rust SEPT SDK</xhtml:a> which, because it was the second pass at coding up
          these concepts, turned out conceptually a bit cleaner, although the codebases don't implement exactly the same thing.  The
          documentation on the Rust SDK repo's front page gives a good description of the project's goals, so I'll leave it there.
          </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Vorpy</name>
        <short-description>VictOR dods' PYthon library</short-description>
        <years>2016-</years>
        <description>
          <xhtml:p>
          <xhtml:a href='https://github.com/vdods/vorpy'>Vorpy</xhtml:a> is a Python math package which does numeric and symbolic
          computation.  It uses <xhtml:a href='https://numpy.org/'>numpy</xhtml:a> and
          <xhtml:a href='https://www.sympy.org/en/index.html'>sympy</xhtml:a> to provide abstractions including, but not limited to:
          <xhtml:ul>
            <xhtml:li>Differential calculus on manifolds</xhtml:li>
            <xhtml:li>Differential symplectic geometry</xhtml:li>
            <xhtml:li>Riemannian symplectic geometry</xhtml:li>
            <xhtml:li>A coordinatized, non-formal version of the strongly-typed tensor calculus in my paper <xhtml:a href='https://doi.org/10.3390/math10183231'>Riemannian Calculus of Variations Using Strongly Typed Tensor Calculus</xhtml:a> (incomplete, experimental)</xhtml:li>
            <xhtml:li>ODE integrators, including an adaptive integrator in which the integration timestep is controlled in order to bound errors on specified quantities</xhtml:li>
            <xhtml:li>Symplectic integrator</xhtml:li>
            <xhtml:li>An integrator which also computes the tangent map of the vector field's flow map</xhtml:li>
            <xhtml:li>Bezier curves and primitives for Bernstein polynomials using a slick tensor-based approach in which your coefficients can be tensor-valued</xhtml:li>
            <xhtml:li>Piecewise linear functions</xhtml:li>
            <xhtml:li>A "lambdify" mechanism which turns a symbolic expression into a Python function, caching the source code to disk for later reloading (useful when the symbolic expression is expensive to compute)</xhtml:li>
            <xhtml:li>Various tensor and linear algebraic constructions</xhtml:li>
          </xhtml:ul>
          The documentation within the codebase isn't quite up to date, so it's probably better to just read the code.  Yeah, I know that's not very user-friendly but there are just so many rad ideas to pursue and I don't have the time to keep everything up to date!
          </xhtml:p>
          <xhtml:p>
          This Python package was used heavily in the research I did with Corey Shanbrom on the Kepler-Heisenberg problem.
          </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Einstein's Eye</name>
        <short-description>ray-tracing-on-manifolds program</short-description>
        <years>2008-</years>
        <description>
            <xhtml:p>
            Einstein's Eye (EE) does ray tracing on manifolds (i.e. curved spaces).
            </xhtml:p>
            <xhtml:p>
            Ordinary <xhtml:a href='http://en.wikipedia.org/wiki/Ray_tracing_%28graphics%29'>ray tracing</xhtml:a> simulates optics for
            generating images of model-based geometry in the following way.  Given a point of view (the eye) and direction of view, one
            generates a pixelated image by "tracing" a ray out from the eye through each pixel on the screen (imagine the pixels form a
            rectangle in front of the eye).  The computer determines the first thing hit by the light ray, and records its color to the
            pixel.  Doing this for all pixels on the screen generates the image.  This is a simplified description of the algorithm - to
            generate photo-realistic images is much more complex.  This is ray tracing in "flat space" (where light
            travels in straight lines).
            </xhtml:p>
            <xhtml:p>
            But say we live inside a curved space (the appropriate mathematical object is a Riemannian manifold). Einstein mathematically proved
            that gravity curves space.  Ostensibly, light must travel paths which stay within the universe, so must follow the curvature of space.
            Due to minimizing properties of the trajectories of light, it must follow what are called "geodesics" - geodesics can be thought of
            as the "straightest lines possible" in the curved space.  The exact formulation of geodesics is (can be) done in the language of the
            calculus of variations.  The approach is the same - follow the light rays until they hit something, then record the color.  The details
            of doing so are more involved, due to the loss of the vector space structure one relies upon in traditional ray tracing. Rather than
            using a simple parametric equation for a line, one must now solve the geodesic equations (a second-order system of ODEs).
            </xhtml:p>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='gravitywell04.png' target='_blank'><xhtml:img src='thumbnails/gravitywell04.png'/></xhtml:a>
                    <xhtml:a href='retardedcat.png' target='_blank'><xhtml:img src='thumbnails/retardedcat.png'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> This is a gravity well (a non-physically-accurate depiction of a black hole) in front of
                    a picture frame (I need to create some room models so there is more context for what's going on in this picture).  The
                    concentric rings are multiple (distorted) images of the picture frame, resulting from the light rays looping around the
                    gravity well a number of times before hitting the picture frame, the closer they pass to the center of the well.
                    <xhtml:strong>Right:</xhtml:strong> For reference, here is the original image for the "picture frame" in the gravity well image.
                </xhtml:div>
            </xhtml:div>
            <xhtml:p>
            There are certain other technical issues such as representing model geometry within a manifold, and more importantly, moving said
            model geometry around the manifold (which may be irregularly curved) in a physically meaningful way.  The visualization is
            straightforward, and even doing rudimentary lighting is relatively easy.  The model geometry and animation is the real challenge. I
            am currently learning elastic and continuum mechanics in order to have a mathematical foundation for solving these problems.
            Undoubtedly the equations (PDEs, most likely) governing motion of an elastic body in a general manifold (think some arbitrary blob
            surface) are intractibly difficult to solve.  Special cases such as homogeneous and/or isotropic manifolds may render tractable
            solutions. Homogeneous and isotropic manifolds should allow for rigid-body mechanics.
            </xhtml:p>
            <xhtml:div class='wide-image-box'>
                <xhtml:center><xhtml:a href='flat_torus_02.png' target='_blank'><xhtml:img src='thumbnails/flat_torus_02.png'/></xhtml:a></xhtml:center>
                <xhtml:div class='caption'>
                    Here, the universe is a flat 3-torus (i.e. space is a cube which wraps on itself like Pacman).  No lighting is done in this
                    rendering; the shading is due to a fog effect applied for objects seen at a distance.  There is only a single globe in the
                    manifold.  The torus wraps back on itself which creates the infinite grid of seen globes.
                </xhtml:div>
            </xhtml:div>
            <xhtml:p>
            In terms of the EE program, numerical methods for approximating solutions to PDEs should be able to handle the general solutions
            (arbitrary manifolds).  Certain special manifolds (spheres, tori, etc) should render closed forms for geodesics which will really
            speed up visualization.  Making use of the GPU for numerically solving the geodesic equations - a highly parallel operation -
            will also give a critical speed-up.  The more subtle methods of ray tracing (use of the
            <xhtml:a href='http://en.wikipedia.org/wiki/Rendering_equation'>rendering equation</xhtml:a>, distance blur, reflections, etc) are planned,
            though these will be a challenge due to a general manifold's lack of a vector space structure. Embedding objects and modeling physics in
            Riemannian manifolds is the subject of my research as a Math Ph.D. student at UCSC.
            </xhtml:p>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='lamp_and_table_03.png' target='_blank'><xhtml:img src='thumbnails/lamp_and_table_03.png'/></xhtml:a>
                    <xhtml:a href='gravity_well_lamp_and_table_00.png' target='_blank'><xhtml:img src='thumbnails/gravity_well_lamp_and_table_00.png'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> This image is again a flat 3-torus, only there is a floor and ceiling added, blocking the
                    sight of the up-and-down repetition. The scene models are more interesting (a lamp and a table), and a light source has been
                    added to the lamp.  The lighting operates via caustics, which is the only method which makes sense in the general case.  A
                    manifold with additional structure (e.g. a space of constant-curvature) could yield easier lighting calculations.
                    <xhtml:strong>Right:</xhtml:strong> Here is a similar scene, slightly rearranged, a globe added to the table.  Only now there
                    is no tiling of space, but instead a gravity well has been added to the manifold.  Notice how the right edge of the table
                    appears to curve downward, making the underside visible.  No physical distortion is happening, it's all a result of the optical
                    lensing effect due to the curvature of space.  The irregularities in the lighting are due to a temporary hack/approximation in the
                    caustic algorithm.
                </xhtml:div>
            </xhtml:div>
            An animated flythrough of the lamp and table with gravity well can be seen <xhtml:a href='gravity_well_lamp_and_table.avi'>here</xhtml:a>.
        </description>
      </subcategory>
      <subcategory>
        <name>LiViD</name>
        <short-description>C++ utility code library</short-description>
        <years>2006-</years>
        <description>
            <xhtml:p>
            LiViD (LIbrary of VIctor Dods, acronymed to LVD) is a small library of C++ utility code, making heavy use of C++
            templates, geared toward being able to plop its source code (or a subset thereof) into a project and go immediately,
            without annoying build logistics.  It is among the most groomed and well-tested code I've written.  Prominently
            featured in the library is a very robust test framework which runs each test in a spawned child process.  This is
            so that the parent process can detect signals sent by the child (segmentation faults, assertion failures, etc).
            This makes the test framework able to handle any type of fault.  While portability is the goal here (since the
            library is very general C++ utility code), I haven't yet attempted a WIN32 compile. Mainly because I utterly
            detest the entire Windows development experience.  So for now, we'll just say it's targeted for Unix.
            </xhtml:p>
            <xhtml:p>
            I created this library mainly because every time I made a new project, there were certain source code files I
            copied verbatim from my old projects (notably the commandline parser class).  LVD is an attempt to provide drop-in
            utility source code.
            </xhtml:p>
            <xhtml:p>
            The current features (as of 2006.06.02) are (* indicates what I've found the most useful):
            </xhtml:p>
            <xhtml:p>
            <xhtml:ul>
            <xhtml:li>Template metaprogramming classes (such as static assert, if-statements, integer types, integer log, integer pow, classes for binary integer literals)</xhtml:li>
            <xhtml:li>A callstack-printing facility (though only if the "addr2line" binary is available, i.e. Unix)</xhtml:li>
            <xhtml:li>* A commandline option parser (very automated, handles short and long options, and prints its own nicely-formatted help message)</xhtml:li>
            <xhtml:li>A class wrapper for making bitflags more strongly typed</xhtml:li>
            <xhtml:li>A class wrapper for making enums more specifiable and strongly typed</xhtml:li>
            <xhtml:li>* A templatized matrix class</xhtml:li>
            <xhtml:li>* A templatized vector class (which works with the matrix class)</xhtml:li>
            <xhtml:li>A templatized, strongly typed printf function (though this will likely be dumped because it generates massive code)</xhtml:li>
            <xhtml:li>A child process spawning utility (used by the test framework)</xhtml:li>
            <xhtml:li>* A test framework (as described above), which is used to test LVD itself</xhtml:li>
            <xhtml:li>Some UTF8 utility functions</xhtml:li>
            <xhtml:li>A simplified XML parser (this uses BARF to generate its scanner and parser classes)</xhtml:li>
            </xhtml:ul>
            </xhtml:p>
            <xhtml:p>
            Emphasis is on simplicity, tidiness and the lack of a massive dependency tree.
            </xhtml:p>
            <xhtml:p>
            Source code is available on <xhtml:a href='https://github.com/vdods/lvd'>Github</xhtml:a>.
            </xhtml:p>
            <xhtml:p>
            Historical releases (kept for nostalgia/laughs):
            </xhtml:p>
            <xhtml:p>
            LVD is free open source software released under the GPL.  The version numbering is as follows. The first number
            is the major revision (an increment to this number indicates a break in compatibility).  The rest of the numbers
            are the release date for the version.
            </xhtml:p>
            <xhtml:p>
            <xhtml:code><xhtml:a href='livid-1.20120911.tar.bz2'>livid-1.20120911.tar.bz2</xhtml:a></xhtml:code>
            </xhtml:p>
            <xhtml:p>
            <xhtml:code><xhtml:a href='livid-1.20100602.tar.bz2'>livid-1.20100602.tar.bz2</xhtml:a></xhtml:code>
            </xhtml:p>
            <xhtml:p>
            Note that if you modify <xhtml:code>lvd_xml_parser.trison</xhtml:code> or <xhtml:code>lvd_xml_scanner.trison</xhtml:code>,
            you'll need trison or reflex (found in BARF), respectively, to re-generate the parser or scanner C++ source files.
            I would not recommend modifying the parser or scanner C++ source files, since they're generated by BARF, and you'll
            lose your changes if you ever re-BARF the trison or reflex sources.
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>BARF</name>
        <short-description>compiler tools</short-description>
        <years>2006-</years>
        <description>
            <xhtml:div class='image-box'>
                <xhtml:center><xhtml:img src='barf.png'/></xhtml:center>
            </xhtml:div>
            <xhtml:p>
            <xhtml:a href='http://barf.sourceforge.net'>BARF</xhtml:a> is a suite of compiler tools I have been working on
            intermittently since 2006.  It is free open source software, released under the GPL license.
            </xhtml:p>
            <xhtml:p>
            It started out as "trison", a replacement to GNU's "bison" LALR(1) parser generator.  I found the code generated
            by bison (and flex) to be abhorrent, and therefore was highly motivated to write my own compiler-compiler.  The
            first version of trison used a source file almost identical to that used by bison, but produced only C++ parsers.
            The C++ framework code was semi-hardcoded and run through a preprocessor to generate each custom parser.
            </xhtml:p>
            <xhtml:p>
            My friend Dan Palm was responsible for the name BARF, suggesting it originally as "Bison's Awesome Replacement
            Framework", which I modified to "Bison Awesomely Replaced, Flex" (i.e. Flex/Bison Awesomely Replaced) after
            adding "reflex", a lexical scanner generator.
            </xhtml:p>
            <xhtml:p>
            Reflex brought a redesign of the preprocessor system, such that arbitrary target languages could be supported
            (though only C++ was targeted at the time) via a "targetspec" and (possibly multiple) "codespec" files.  The
            targetspec describes what directives are available to reflex to customize the generated scanner code, and the
            codespec is a preprocessor file containing the framework code. This design essentially turned reflex into a
            fancy preprocessor - all it does is generate a DFA and then munge the appropriate targetspec and codespec files
            in the manner of a preprocessor, macros and everything, to output the desired scanner code.
            </xhtml:p>
            <xhtml:p>
            Trison was eventually adapted to this design as well, which allowed a significant amount of code to be shared
            between the two programs.  The original trison supported only LALR(1) grammars, but the revamp allowed LALR(k)
            via NPDAs and eventually DPDAs (though the DPDA-generating algorithm, while functional, is aesthetically
            displeasing and somewhat incomplete).
            </xhtml:p>
            <xhtml:p>
            Currently only C++ targets have been written, but the textfile-based model allows for additional target languages
            to be added without having to recompile the tools.  Support for a Python target is not yet possible due to
            Python's indentation-based scoping, though I do want to add such support because Python is neat.
            </xhtml:p>
            <xhtml:p>
            Source code (also available on <xhtml:a href='http://sourceforge.net/projects/barf/'>Sourceforge</xhtml:a> via svn):
            </xhtml:p>
            <xhtml:p>
            <xhtml:code><xhtml:a href='barf-0.9.20101002.tar.bz2'>barf-0.9.20101002.tar.bz2</xhtml:a></xhtml:code>
            </xhtml:p>
            <xhtml:p>
            <xhtml:code><xhtml:a href='barf-0.9.20100116.tar.bz2'>barf-0.9.20100116.tar.bz2</xhtml:a></xhtml:code>
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>XRB</name>
        <short-description>2D game engine</short-description>
        <years>2004-</years>
        <description>
            <xhtml:div class='image-box'>
                <xhtml:center><xhtml:a href='disasteroids/numbskull.png' target='_blank'><xhtml:img src='thumbnails/disasteroids/numbskull.png'/></xhtml:a></xhtml:center>
                <xhtml:div class='caption'>
                    The original "sdl_test" program, displaying a skull-and-crossbones spinning around the screen. The strange visual
                    echoes were actually a cool-looking bug in the rendering code (this was before I switched everything to OpenGL).
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='image-box'>
                <xhtml:center><xhtml:a href='disasteroids/screenshot2.png' target='_blank'><xhtml:img src='thumbnails/disasteroids/screenshot2.png'/></xhtml:a></xhtml:center>
                <xhtml:div class='caption'>
                    From after "sdl_test" became XRB.  Still with software rendering, a screenshot demonstrating some of the GUI layout
                    capabilities and the transparency.  In the background is a WorldViewWidget, which is what renders the game world.
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='image-box'>
                <xhtml:center><xhtml:a href='disasteroids/mapeditor4.png' target='_blank'><xhtml:img src='thumbnails/disasteroids/mapeditor4.png'/></xhtml:a></xhtml:center>
                <xhtml:div class='caption'>
                    Here is probably the nicest-looking screenshot made of the map editor, showing the physical parameters of Entity objects
                    being modified (the green arrows are the linear velocities of each object).  The grid was adaptive and faded out as the
                    view zoomed out, to reveal the next larger scale grid. Similarly for zooming in.  I was quite proud of how well the user
                    interface worked - moving/rotation/ scaling/selection/etc actions were performed using the mouse, mouse buttons and
                    shift/alt/ctrl keys. Creating and editing objects was very quick and easy.
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='image-box'>
                <xhtml:center><xhtml:a href='disasteroids/mapeditor8.png' target='_blank'><xhtml:img src='thumbnails/disasteroids/mapeditor8.png'/></xhtml:a></xhtml:center>
                <xhtml:div class='caption'>
                    Editing polygonal object vertices in the map editor.
                </xhtml:div>
            </xhtml:div>
            <xhtml:p>
            <xhtml:a href='http://xuqrijbuh.sourceforge.net'>XRB</xhtml:a> (which stands for 'XuqRijBuh', a random name I made up a
            long time ago for a video game which has the advantage of not being used anywhere else by anyone) is a sprite-based 2d game engine I have
            been working on intermittently since 2004.  It is free open source software, released under the GPL license.  What started
            out as a scratch program called "sdl_test" to test out and learn <xhtml:a href='http://www.libsdl.org/'>SDL</xhtml:a>
            turned into a full-fledged game engine. Originally it used the SDL framebuffer and did all rasterization in software.
            The rendering code was fun to develop, but no modern game does graphics in software, so soon OpenGL supplanted the
            software rendering code.
            </xhtml:p>
            <xhtml:p>
            I created a pretty detailed map editor to fill what I saw would be a large need for map creation. Sprite and polygonal
            object creation was finely controllable, with velocities, angular velocities and so forth.  As XRB developed, the boring
            test application turned into Disasteroids, a game which I would describe as a super-violent asteroids on crack.
            Disasteroids used only dynamic game world generation, so the map editor lay unused for a long time, and became more
            outdated as I grew lazy and didn't bother maintaining it.  Eventually I met someone who gave me the idea of using SVG
            files for the game maps.  Using (a subset of) this standard format allows any vector-based graphics editor (such as
            <xhtml:a href='http://www.inkscape.org/'>Inkscape</xhtml:a> to be used as a map editor.  While there will be less
            game-specific integration in such a graphics editor, the lack of a need for maintainence is appealing.  Inkscape's XML
            editor mode allows the user to add attributes and elements to map sprites to provide game-specific information about
            each object.
            </xhtml:p>
            <xhtml:p>
            I later added support for polygonal objects, for which vertex editing was necessary.  This was a much more difficult
            interface to create, and while never fully completed before its timely demise, it was also quick and easy to use.  I
            hadn't got around to adding the capability to edit texture UV coordinates.<xhtml:br/>
            </xhtml:p>
            <xhtml:p>
            I would really have liked to have had the time to maintain the map editor in parallel with the engine as it evolved.
            As it stood though, I hadn't created any application which actually required the map editor (such as a platformer game
            with lots of levels).  I'm hoping that because SVG files can be made by many common illustration programs (e.g. Adobe
            Illustrator, Inkscape, etc), it will be easier for artists to create assets for XRB games.<xhtml:br/>
            </xhtml:p>
            <xhtml:p>
            Disasteroids was originally designed to be an example app to test and demonstrate XRB.  It inevitably grew into a
            full-fledged game, and while not finished, could be considered a feature-complete arcade game.  There are 5 types of
            enemies, each coming in 4 different levels, indicated by their colors and sizes.  There are shields, armor, engines and
            7 different weapons (also each coming in 4 different levels).  There is a tractor beam "weapon" which facilitates
            collection of the minerals necessary to buy and upgrade items.  The tractor beam operates in 3 modes: the green mode
            sucks up only goodies (minerals and health powerups), the blue mode sucks up everything (Devourment and Demi, the two
            large enemy types, each use this mode), and the red mode pushes everything away (useful for deflecting attacks, also
            used by Demi).
            </xhtml:p>
            <xhtml:p>
            I made the ship artwork in Inkscape, and am sort of proud of it.  Most of the other artwork in the game is more or
            less engineer placeholder art, and needs to be done for real.  I originally made sketches of each of the ships while
            bored in a meeting at work.  I sketched a lot of ideas for a platformer game I'm planning for the unspecified future
            as well, but that's another story.  The visual style for Devourment and the enemy level palette-variation were inspired
            by the SEGA games Fantasy Zone and Phantasy Star respectively.
            </xhtml:p>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:img src='disasteroids/interloper0_small.png'/>
                    <xhtml:img src='disasteroids/interloper1_small.png'/>
                    <xhtml:img src='disasteroids/interloper2_small.png'/>
                    <xhtml:img src='disasteroids/interloper3_small.png'/>
                </xhtml:center>
                <xhtml:div class='caption'>
                    Interlopers ram the player to cause collision damage.  They flock together and swarm the player in massive numbers.
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:img src='disasteroids/shade0_small.png'/>
                    <xhtml:img src='disasteroids/shade1_small.png'/>
                    <xhtml:img src='disasteroids/shade2_small.png'/>
                    <xhtml:img src='disasteroids/shade3_small.png'/>
                </xhtml:center>
                <xhtml:div class='caption'>
                    Shades mimic the velocity of the player to "float" nearby and fire slow-moving bullets.  They can teleport away when threatened.
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:img src='disasteroids/revulsion0_small.png'/>
                    <xhtml:img src='disasteroids/revulsion1_small.png'/>
                    <xhtml:img src='disasteroids/revulsion2_small.png'/>
                    <xhtml:img src='disasteroids/revulsion3_small.png'/>
                </xhtml:center>
                <xhtml:div class='caption'>
                    Revulsions attack with Gauss guns when the player's back is turned, but will flee when looked at directly.
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:img src='disasteroids/devourment0_small.png'/>
                    <xhtml:img src='disasteroids/devourment1_small.png'/>
                    <xhtml:img src='disasteroids/devourment2_small.png'/>
                    <xhtml:img src='disasteroids/devourment3_small.png'/>
                </xhtml:center>
                <xhtml:br/>
                <xhtml:center>
                    <xhtml:img src='disasteroids/grinder0_small.png'/>
                    <xhtml:img src='disasteroids/grinder1_small.png'/>
                    <xhtml:img src='disasteroids/grinder2_small.png'/>
                    <xhtml:img src='disasteroids/grinder3_small.png'/>
                </xhtml:center>
                <xhtml:div class='caption'>
                    Devourments want only to consume.  While not directly aggressive to the player, they will pursue and suck up anything
                    that nears their grinder maws, including other enemies.  Their normal diet consists of asteroids. When killed,
                    potentially many minerals (and health powerups) are released, making the difficult investment of destroying a Devourment
                    worth it.
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:img src='disasteroids/demi0_small.png'/>
                    <xhtml:img src='disasteroids/demi1_small.png'/>
                    <xhtml:img src='disasteroids/demi2_small.png'/>
                    <xhtml:img src='disasteroids/demi3_small.png'/>
                </xhtml:center>
                <xhtml:div class='caption'>
                    Demi is the boss enemy.  Equipped with many weapons and tractor beams, they vary their attacks and continually
                    harass the player (for example if the player attempts to flee, a Demi will either charge the player or use its
                    powerful tractor beam to fling the player back into the line of fire).
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:img src='disasteroids/solitary_small.png'/>
                </xhtml:center>
                <xhtml:div class='caption'>
                    Here's our hero, "Solitary".  This term comes from my friend Chris Messineo who described the awesomeness of the
                    idea that in a shoot-em-up-style game, a small, solitary ship takes on overwhelming swarms of enemies and emerges
                    in triumph.  (Though to give fair warning, in Disasteroids, the waves keep coming and the game continues until
                    the player dies in glorious battle!)
                </xhtml:div>
            </xhtml:div>
            <xhtml:p>
            Here are some in-game screenshots.  Unfortunately the hectic action is not captured properly in still shots (mental note: motion-blurred screenshots).
            </xhtml:p>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='disasteroids/disasteroids010.png' target='_blank'><xhtml:img src='thumbnails/disasteroids/disasteroids010.png'/></xhtml:a>
                    <xhtml:a href='disasteroids/disasteroids011.png' target='_blank'><xhtml:img src='thumbnails/disasteroids/disasteroids011.png'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> Swarms of Interlopers rush from offscreen in each wave.  <xhtml:strong>Right:</xhtml:strong> Devourments will eat anything, including other enemies.
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='disasteroids/disasteroids013.png' target='_blank'><xhtml:img src='thumbnails/disasteroids/disasteroids013.png'/></xhtml:a>
                    <xhtml:a href='disasteroids/disasteroids021.png' target='_blank'><xhtml:img src='thumbnails/disasteroids/disasteroids021.png'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> A Demi (the boss enemy) spraying flames.  <xhtml:strong>Right:</xhtml:strong> Zooming out in debug mode shows the game world tiling.
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='disasteroids/disasteroids040.png' target='_blank'><xhtml:img src='thumbnails/disasteroids/disasteroids040.png'/></xhtml:a>
                    <xhtml:a href='disasteroids/disasteroids043.png' target='_blank'><xhtml:img src='thumbnails/disasteroids/disasteroids043.png'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> The player attacks a 2nd level Demi with grenades.  <xhtml:strong>Right:</xhtml:strong> Exploding bosses spawn goodies and baddies.
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='disasteroids/disasteroids044.png' target='_blank'><xhtml:img src='thumbnails/disasteroids/disasteroids044.png'/></xhtml:a>
                    <xhtml:a href='disasteroids/disasteroids047.png' target='_blank'><xhtml:img src='thumbnails/disasteroids/disasteroids047.png'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> The EMP shockwave weapon disables enemies within its blast radius.  <xhtml:strong>Right:</xhtml:strong> Mid-game carnage.
                </xhtml:div>
            </xhtml:div>
            <xhtml:p>
            XRB uses SDL and <xhtml:a href='http://www.khronos.org/opengles/'>OpenGL ES</xhtml:a> for maximum platform compatibility
            (the Linux, Mac OS X, Windows and iPhone platforms have working builds).  There is a (nearly) complete GUI system
            (modeled loosely after QT) including a decent font engine.  The fonts are generated at runtime using the FreeType
            library, and then cached for later loading.  This allows builds without linking the
            <xhtml:a href='http://freetype.sourceforge.net/index2.html'>FreeType</xhtml:a> library to use previously cached font data.
            Much effort went into creating an easy-to-use widget layout system, so that widgets are positioned and sized automatically,
            without much user interference.  Any screen size is easily handled, with font sizes being based on the screen height.
            Thus the game takes on the same proportions (widget proportions, font proportions, etc) for any proportional resolutions.
            <xhtml:a href='http://www.libpng.org/pub/png/libpng.html'>Libpng</xhtml:a> is used for image loading/saving.
            </xhtml:p>
            <xhtml:p>
            The rendering system is simple yet robust, allowing for color masking and biasing through the GUI widget hierarchy and
            game world view.  Transparent objects are supported and ordered so as to be rendered correctly. There is a set of
            abstract classes in the Engine2 namespace which provide a framework on which to build game-specific code.  These
            classes include [game] World class (which controls the game world), the PhysicsHandler class (which is an interface
            that World uses to run the game physics), the Entity class (for animate objects), etc.  Currently (2010.06.02) there
            is no sound.  This is something I hope to remedy soon, since XRB has gone silent long enough.
            </xhtml:p>
            <xhtml:p>
            I have written some <xhtml:a href='http://xuqrijbuh.sourceforge.net/lessons.html'>lesson applications</xhtml:a>,
            annotated with Doxygen comments, to incrementally teach usage of the XRB library.
            </xhtml:p>
            <xhtml:p>
            Ben Nichols and I have ported XRB to the iPhone/iPod Touch platform for future game development. Porting to this
            platform involved abstracting the use of all libraries to the "PAL" interface (Platform Abstraction Layer).  This
            includes image and font loading, image saving, timing mechanisms, setting video modes, etc.  SDL, libpng and
            FreeType - the libraries of choice for the desktop platforms - were hidden behind this interface.  A minimal
            iPhone PAL was created to use what was provided by the iPhone APIs, as well as to avoid unnecessary library
            dependency - the use of SDL, libpng and FreeType was avoided.  The other main difficulty in the iPhone port
            was to "downgrade" the use of OpenGL to <xhtml:a href='http://www.khronos.org/opengles/'>OpenGL ES</xhtml:a>.
            It wasn't so much a downgrade, as no functionality was lost (XRB doesn't need much in the way of OpenGL, and
            doesn't really do anything too fancy).
            </xhtml:p>
            <xhtml:p>
            While everything worked without too much trouble, the original performance was terrible.  Certain techniques
            were needed to cut down render time.  Texture atlases (a technique of packing multiple sprites into one OpenGL
            texture to cut down on the overhead of switching textures) were implemented.  This was difficult to do while
            preserving all the mipmap functionality XRB had grown used to.  I came up with a fancy way to pack different
            sized textures in a careful way so their mipmaps wouldn't overlap.  Actual empirical data on the packing
            efficiency is still needed however.  Another optimization was to do as much matrix math as possible in
            software. This provided a speedup, since full 4x4 matrices are not necessary in a 2d game world.  These
            optimizations, along with a few others, rendered a decent speedup.  Additionally, I added a screen- rotation
            feature, so that rendering could be done at any angle (any multiple of 90 degrees), i.e. on an iPhone when
            it flips to the side.
            </xhtml:p>
            <xhtml:p>
            The iPhone platform code is private and is not included in the Sourceforge repository, but it's really not
            hard to implement your own iPhone PAL.
            </xhtml:p>
            <xhtml:p>
            Here is an ASCII-art <xhtml:a href='http://en.wikipedia.org/wiki/Quine_%28computing%29'>quine</xhtml:a> I wrote to use
            as a logo for "XRB GAMES" which is the quasi-real studio name I'm going to slap on the games I produce with XRB.
            </xhtml:p>
            <xhtml:p>
            <xhtml:code><xhtml:a href='xrb_games_quine.c'>xrb_games_quine.c</xhtml:a></xhtml:code>
            </xhtml:p>
            <xhtml:p>
            Source code available on <xhtml:a href='https://github.com/vdods/xrb'>Github</xhtml:a>.
            </xhtml:p>
        </description>
      </subcategory>
    </subcategories>
  </category>
  <category>
    <title>Completed and inactive software projects</title>
    <subcategories>
      <subcategory>
        <name>Mumpy</name>
        <short-description>A surprisingly good made-up word generator with a surprisingly crappy web interface</short-description>
        <years>2020-2021</years>
        <description>
          <xhtml:p>
          <xhtml:a href='https://itdont.work/mumpy'>Try it out!</xhtml:a>
          </xhtml:p>
          <xhtml:p>
          Instructions: In the "Corpus Selection" column, pick a training corpus (for example, "Female Names") and click
          "Load This Corpus".  This loads that corpus into the "Training Stage" column (which can be edited by hand if desired).
          Then click on "Learn This Content", which will populate "Trained Model" with statistics about the model.  Finally,
          click "Reseed, Generate" to sample the model to generate made-up text based on that model.  The "Learn This Content"
          button works additively on a model, so you can combine different training corpuses (I suggest "Female Names" and
          "Death Metal Band Names", though you may need to weight the death metal corpus extra by clicking "Learn This
          Content" multiple times relative to the female names corpus) and it will generate text which is a convincing
          blend of the trained input.
          </xhtml:p>
          <xhtml:p>
          I've been trying to get my friends who have been having babies to use this to generate a unique and awesome name.
          No one has admitted (YET) to having used it, but I suspect some might have.  Though for the record, my friends
          Dave and Charlie Stellar picked their kid's unique and awesome name themselves.
          </xhtml:p>
          <xhtml:p>
          Here's a selection generated from a combo of "Female Names" (weight 1, meaning you must click once on "Learn
          This Content" for this corpus) and "Death Metal Band Names" (weight 2, meaning you must click twice on "Learn
          This Content" for this corpus) and the seed <xhtml:code>hH8u6dnRy2ze08sl</xhtml:code>.  Theoretically you should
          get the exact same output (until I change the build, ha).  The number following the name is something like the
          log-likelihood of that particular string being generated from the model.
          <xhtml:ul>
            <xhtml:li>Aeonediction : -6.97</xhtml:li>
            <xhtml:li>Alisarmelin : -7.49</xhtml:li>
            <xhtml:li>Arabeline : -5.45</xhtml:li>
            <xhtml:li>Ardie : -4.04</xhtml:li>
            <xhtml:li>Charlee : -4.13</xhtml:li>
            <xhtml:li>Cryptica : -4.78</xhtml:li>
            <xhtml:li>Daising : -5.63</xhtml:li>
            <xhtml:li>Dany : -3.67</xhtml:li>
            <xhtml:li>Election : -4.47</xhtml:li>
            <xhtml:li>Erth : -4.38</xhtml:li>
            <xhtml:li>Fearse : -4.35</xhtml:li>
            <xhtml:li>Georguts : -4.17</xhtml:li>
            <xhtml:li>Hollyah : -5.40</xhtml:li>
            <xhtml:li>Ilista : -6.22</xhtml:li>
            <xhtml:li>Illding : -4.92</xhtml:li>
            <xhtml:li>Izzie : -3.95</xhtml:li>
            <xhtml:li>Kalis : -4.96</xhtml:li>
            <xhtml:li>Lucilippa : -5.55</xhtml:li>
            <xhtml:li>Lurlina : -4.44</xhtml:li>
            <xhtml:li>Malyangery : -8.29</xhtml:li>
            <xhtml:li>Martguelandie : -7.47</xhtml:li>
            <xhtml:li>Marye : -4.31</xhtml:li>
            <xhtml:li>Mauredra : -5.25</xhtml:li>
            <xhtml:li>Myrtlelone : -6.86</xhtml:li>
            <xhtml:li>Philipping : -5.32</xhtml:li>
            <xhtml:li>Sacrophia : -5.82</xhtml:li>
            <xhtml:li>Saudie : -4.66</xhtml:li>
            <xhtml:li>Tawn : -4.28</xhtml:li>
            <xhtml:li>Vomina : -4.29</xhtml:li>
            <xhtml:li>Wilhelene Post Stodda : -11.51</xhtml:li>
          </xhtml:ul>
          </xhtml:p>
          <xhtml:p>
          More coming soon, including source code (which is Rust, compiling into Wasm and built into a client-side-only web app using Yew Stack)...
          </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Tensor Heaven</name>
        <short-description>C++ multilinear algebra library</short-description>
        <years>2013</years>
        <description>
            <xhtml:p>
            Tensor Heaven began life in discussions between myself and Gabriel Hare at Leap Motion, about the need
            for a C++ tensor algebra library that takes advantage of symmetries present in many tensor algebra
            problems.  Our searching did not turn up any C++ library capable of what we needed.  I did a lot of
            work in tensor algebra/calculus formalism during grad school, and so I had many strong opinions on the
            matter.  My existing C++ expertise was a perfect match for the situation, and soon after, I began work
            on a simple C++ implementation of the needed concepts.
            </xhtml:p>
            <xhtml:p>
            At about the same time, I had lined up my friend from grad school Ted Nitz, who had recently graduated,
            to be hired at Leap, and one of his first tasks was devising and implementing the indexing scheme for
            antisymmetric tensors.  Many mathematical discussions were had between Ted, Gabe, and myself.  Ted and I
            would hold 'design meetings' where we would discuss conceptual and implementation details of the project
            over glasses of scotch.  Ted and I worked full time on Tensor Heaven for quite some time, and it was by far
            the most enjoyable project I've worked on in a professional capacity.  I was contracting 3 days per week at
            Leap at that time, and I was able to work on Tensor Heaven remotely from Herräng Dance Camp in Sweden for
            4 weeks in the summer of 2013.  My dream job would be working remotely, in a small team, on projects like
            Tensor Heaven.
            </xhtml:p>
            <xhtml:p>
            Part of the development effort went into doing research in linear algebraic category theory, for which
            I wrote a <xhtml:a href='papers/20130423-linear-algebraic-cat-theory-for-prog.pdf'>detailed mathematical document</xhtml:a>.
            The relevant thing here is the category of based vector spaces; an object
            in this category is a vector space with a choice of a basis, while a morphism is a domain based vector space,
            a codomain based vector space, and a matrix specifying the linear transformation in the respective bases.
            Based tensor spaces and other related things are built in a natural way out of these.
            We proved some results which were nontrivially useful in the C++ implementation, in particular, that a
            particular isomorphism of based tensor spaces rendered the identity matrix, and therefore the two spaces,
            when represented as a tuple of values in computer memory, could be identified without any memory copy
            operations.
            </xhtml:p>
            <xhtml:p>
            Category theory also found a tremendous application not only in clarifying the relevant linear algebraic
            theory, but also in suggesting an organizational technique for the C++ implementation.  Category theory concerns
            itself only with the high-level structure of mathematical relationships, not with the particulars such as
            solutions to equations and such.  As such, what was suggested was the stratification of the Tensor Heaven
            source code into two layers: conceptual and implementation.  The conceptual layer (which we considered calling
            the 'categorical layer' for a time, but instead went with a more general term for purposes of flexibility) is
            intended to encode only the mathematical structures and relationships provided by the library.  The
            implementation layer specifies the implementation details for the structures and relationships defined in the
            conceptual layer.  Thus there is a clean, functorial correspondence between concept and implementation (e.g.
            concept A, implementation of concept A).  The stratification into these layers also avoids the problem of
            other complex mathematical software (such as the C++ linear algebra library Eigen) of trying to conflate the
            mathematical structure with the C++ class hierarchical structure.  It has been my experience in writing
            mathematical software (in Tensor Heaven and in Einstein's Eye) that C++ class hierarchies are not flexible
            enough to faithfully represent rich mathematical structures.
            </xhtml:p>
            <xhtml:p>
            A significant portion of my work in grad school involved developing a 'strongly typed' formalism for tensor
            algebra and calculus.  My background in programming had seeded my mind with the notion of a strongly typed
            programming language (loosely defined as a programming language which guarantees that only well-defined
            expressions are constructible), and that lent itself naturally to devising and using such a formalism
            for tensor algebra and calculus.  While not [yet] computerized, the point of the tensor formalism was to
            provide an explicit means for checking the validity of tensor expressions, which can get incredibly complex
            and are very subject to human error.  The work I did later for my PhD dissertation used this formalism
            and prevented countless headaches normally induced by performing calculations in index notation, thereby
            proving its value at least in my eyes.  This formalism was implemented in Tensor Heaven.  In particular,
            each tensor factor has a 'type' (the name of a vector space or its dual), which can only be paired (composed)
            with a factor of dual type.  This 'natural pairing' is checked at compile time, and compile errors are
            produced if the expression is ill-defined.  Because tensor expressions can be so involved, this correctness
            checking provides a significant advantage over using un-typed tensors, for which the human programmer must
            mentally account for the correctness of the expression.  There are other subtle advantages that this provides
            as well, which will be written about elsewhere.
            </xhtml:p>
            <xhtml:p>
            I eventually got Tensor Heaven open-sourced, and it is currently available
            <xhtml:a href='https://github.com/leapmotion/tensorheaven'>on Github</xhtml:a> under the Apache 2 license.
            While many important features are implemented, there are still some important features that Ted and I didn't
            have time to get to.  The main one is induced inner products on all constructible spaces (such as tensor powers,
            symmetric and antisymmetric powers, etc).  Having an inner product on a space is necessary in order to perform
            any sort of least-squares optimization on that space.  It is incorrect in general to use the standard inner
            product in the given basis; for example on the space of symmetric 2-tensors (aka symmetric matrices), the
            diagonal and off-diagonal entries have multiplicity 1 and 2 respectively -- these weights must be taken
            into account by the inner product, whereas the standard inner product assumes they're all 1.
            </xhtml:p>
        </description>
      </subcategory>
    </subcategories>
  </category>
  <category>
    <title>Music</title>
    <subcategories>
      <subcategory>
        <name>HACKSAW TO THE THROAT</name>
        <short-description>progressive/syncopated/melodic death/thrash/grind</short-description>
        <years>2002-2008</years>
        <description>
            <xhtml:p>
            <xhtml:a href='http://hacksawtothethroat.com/'>Look</xhtml:a> and <xhtml:a href='http://hacksawtothethroat.com/albums/'>listen</xhtml:a>.
            The second link is MP3s of all our studio-recorded music, including our two full-length albums.
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Black Swan Events</name>
        <short-description>western classical/heavy metal musical collaboration with Nick Vasallo</short-description>
        <years>2013</years>
        <description>
            <xhtml:p>
            <xhtml:a href='http://nickvasallo.com/'>Nick Vasallo</xhtml:a>, my friend from ten years earlier in our band days, asked me to
            compose and perform a cadenza for his doctoral composition (for his doctoral degree in music) while we were both
            grad students at UC Santa Cruz.  I wrote a solo in my thrash metal style, and we worked a little bit on it so that it would fit
            into his 16-minute long orchestral composition.  Later, Nick recorded the piece with live musicians, including me, and later still,
            we filmed <xhtml:a href='https://www.youtube.com/watch?v=CfbHo1p2uuM'>a video</xhtml:a> for the piece.  It was filmed and edited
            by Brandon Hunt, who also did the excellent filming and editing for a number of Oblivion music videos.
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Oblivion</name>
        <short-description>blackened technical death metal</short-description>
        <years>2011-2019</years>
        <description>
            <xhtml:p>
            Nick Vasallo asked me to join <xhtml:a href='https://en.wikipedia.org/wiki/Oblivion_(metal_band)'>Oblivion</xhtml:a> in 2011 after
            having composed and recorded their first album, <xhtml:a href='http://obtainoblivion.bandcamp.com/album/called-to-rise'>Called to Rise</xhtml:a>.
            I joined in time to film videos for the songs <xhtml:a href='https://www.youtube.com/watch?v=RTnBFIAbFjo'>Reclamation</xhtml:a>,
            <xhtml:a href='https://www.youtube.com/watch?v=4wAXLDCHTGE'>Canon 1 in E minor</xhtml:a>, and
            <xhtml:a href='https://www.youtube.com/watch?v=tkE3dB9Xl2I'>Multiverse</xhtml:a>.  These three videos were filmed and directed
            by Brandon Hunt.  The songs are really technically challenging to play, definitely push me to the limit of my abilities,
            and motivate me to actually learn correct guitar technique :)
            </xhtml:p>
        </description>
      </subcategory>
    </subcategories>
  </category>
  <category>
    <title>Academic math work</title>
    <subcategories>
      <subcategory>
        <name>Riemannian Calculus of Variations using Strongly Typed Tensor Calculus</name>
        <!-- <short-description>a monograph developing a 'strongly typed' tensor calculus formalism and applying it to developing basic calculus of variations in a Riemannian setting</short-description> -->
        <years>2011-2012, 2022</years>
        <description>
            <xhtml:p>
            <xhtml:a href='https://doi.org/10.3390/math10183231'>This paper</xhtml:a>
            (<xhtml:a href='papers/2022-riemannian-calculus-of-variations-published.pdf'>published PDF</xhtml:a> and its
            <xhtml:a href='http://arxiv.org/abs/1212.2376'>preprint</xhtml:a>, which notably includes a table of contents)
            comes in two parts.  The first develops a formalism for doing tensor calculus (and algebra) inspired
            by the 'strongly typed' concept of programming languages (a more student-friendly presentation of the linear
            algebraic concepts here is presented in
            <xhtml:code><xhtml:a href='papers/20120405-tensor-heaven.pdf'>20120405-tensor-heaven.pdf</xhtml:a></xhtml:code>.
            The second part develops a basic toolset for doing calculus of variations on maps between Riemannian manifolds.
            This form of calculus of variations was motivated by the mathematical needs of the elastic mechanical theory in
            my PhD research.
            </xhtml:p>
            <xhtml:p>
            A 'strongly typed' programming language is one which performs certain checks on the source code to ensure that all
            expressions and formulations are well-defined (and therefore, arguably meaningful).  These checks are a boon to
            the programmer, because they will catch a large class of semantical errors at an early stage of development, and
            these sorts of errors are typically very easy to fix.
            </xhtml:p>
            <xhtml:p>
            Tensor calculus is typically done by using what's referred to as 'Einstein index notation' which is a terse and
            flexible technique for expressing the myriad ways that tensors can be composed.  The indices themselves are a notational
            mechanism for indicating which tensor factors are to be composed together.  Because of the proliferation of indistinct
            indices, it's very easy to make mistakes in index-based computations.  In particular, besides a notion of
            'up/down index pairing', there is no way to determine if an index-notation expression is well-defined based on the types
            of the tensors' factors, and therefore detecting mistakes in the computations is very difficult.
            </xhtml:p>
            <xhtml:p>
            The tensor calculus formalism developed within this paper creates a uniform and rich 'type system' which
            tensor fields inhabit, and from which their semantic uses and meanings can be inferred.  For a subclass of
            tensor expressions, index notation can be replaced by in-line contraction notation, where adjacent tensor
            factors are composed with each other, using a type-indicating subscript on the composition operator to
            indicate to the human the meaning of the composition.  This forms the basis of the [still human-driven]
            type checking, but I found that it really improves the experience of doing tensor computations, because
            errors are quickly found.  This advantage is more and more useful as the complexity of the computations
            increases, which was certainly the case in the development of the calculus of variations in the Riemannian
            setting.
            </xhtml:p>
            <xhtml:p>
            The type system used in this tensor calculus formalism will also lend itself neatly to computer-based
            and computer-assisted computations.  This is partly due to the uniformity of the type system and the
            notation.  This is the subject of some of my future work.
            </xhtml:p>
            <xhtml:p>
            I had attempted to publish this paper in 2012, and had gotten positive reviews from both reviewers, and
            while one reviewer accepted it, the other rejected it on the opinion that I should have also provided the
            computer-assisted type checking described in the "Questions and Future Work" section of the preprint.  Given
            that the work itself was already quite long simply laying out the theoretical groundwork, I considered that
            to be an unreasonable request, and gave up on the publication.  Other priorities came up (in particular my
            PhD dissertation, as well as starting work as a researcher for Leap Motion in San Francisco), and the paper
            was left unpublished for 10 years.  Publishing is not a high priority for me, not being a professional academic,
            though I do somewhat regret not having followed up earlier.  However late is better than never, and
            <xhtml:a href='https://www.mdpi.com/journal/mathematics/special_issues/Riemannian_Manifolds'>this special issue</xhtml:a>
            seemed like a perfectly appropriate place to publish.  There are several pieces of research I had done in grad
            school that depend on the material developed in this paper, and now I'm finding fresh motivation to resume work
            to publish what I already have, and to resume research along those avenues.
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Self-similarity in the Kepler-Heisenberg Problem</name>
        <short-description>with Corey Shanbrom</short-description>
        <years>2018-2021</years>
        <description>
            <xhtml:p>
            This was a continuation of the research on Kepler-Heisenberg with my friend Corey Shanbrom, who at that point was
            a professor at CSU Sacramento.  I had the privilege of spending Fall 2018 semester in residence at
            <xhtml:a href='https://www.msri.org/'>MSRI</xhtml:a> for the
            <xhtml:a href='https://www.msri.org/programs/305'>Hamiltonian Systems</xhtml:a> program.  During this semester,
            I continued with the numerical experimentation Corey and I had started with our previous research.  Having found
            some satisfying results on the closed orbits of the Kepler-Heisenberg problem, we decided to focus our attention
            on the zero-energy orbits of the problem in general (all closed orbits are zero-energy, but the converse is false).
            </xhtml:p>
            <xhtml:p>
            We did a lot of numerical investigation again, trying different integration schemes, eventually creating an
            adaptive Runge-Kutta integrator which adjusts its time steps to bound estimates of integration error on whichever
            quantities we defined.  Obviously the Hamiltonian was the most salient quantity, since it's conserved along trajectories.
            However, because the system is Hamiltonian, and therefore its flow is a symplectomorphism, we could track the error in
            the "symplecticity" of the derivative of the flow map using a
            <xhtml:a href='papers/20120417-differentiating-solution-to-ode.pdf'>result</xhtml:a> I had developed several years
            earlier during grad school.  This approach produced very good results.
            </xhtml:p>
            <xhtml:p>
            From these numerical explorations, we conjectured that all zero-energy orbits (with minor restrictions)
            had a self-similar structure, being determined entirely by one (of any choice of) fundamental domain.  Interestingly,
            the self-similarity wasn't just quasi-periodicity, nor was it simply invariance under a group action on the
            configuration space, but rather the self-similarity involved a spatial transformation coupled with a time reparameterization.
            The orbits in general were these beautiful, spiraling, flowery fractals.  After some work, we were able to prove the conjecture.
            To me, this was a rather ideal approach -- computer-based empirical exploration, conjecture, proof.
            </xhtml:p>
            <xhtml:p>
            <xhtml:a href='https://doi.org/10.1007/s00332-021-09709-1'>Article link</xhtml:a>,
            <xhtml:a href='papers/2021-kepler-heisenberg-self-similarity--published.pdf'>Paper</xhtml:a>.
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Numerical Methods and Closed Orbits in the Kepler-Heisenberg Problem</name>
        <short-description>with Corey Shanbrom</short-description>
        <years>2014-2018</years>
        <description>
            <xhtml:p>
            This was a work with my friend Corey Shanbrom which came out of research that he had done for his dissertation at UCSC
            on the Kepler-Heisenberg problem (in which the Kepler problem is posed within the 3D Heisenberg group -- a sub-Riemannian
            manifold).  He had found indications that there were closed orbits having complex shapes, and we set out to study these
            orbits.  In 2014, Corey had obtained a Research &amp; Creative Activity Mini-Grant from CSU Sacramento where he had
            recently started work as associate professor, and this was a great excuse to get together to work on math and drink fancy
            beer.  The collaboration proceeded at a pretty relaxed pace, which kept it fun.
            </xhtml:p>
            <xhtml:p>
            The research took an empirical approach in which we used various numerical methods to find approximate closed solutions
            to the Kepler-Heisenberg problem.  Given the nature of the Heisenberg group, it turned out to be more difficult to
            analyze numerically than expected.  One early attempt used an approach inspired by one used by Michael Nauenberg (UCSC)
            in which he sought approximate solutions to periodic orbits of a 2D dynamical system using variational methods on
            a finite Fourier series.  However we ran into difficulties adapting this approach to our system, which in some sense
            was "quasi-2D" -- the sub-Riemannian structure of the 3D Heisenberg group causes the z coordinate of a Kepler-Heisenberg
            orbit to be almost fully determined by the orbit projected into the (x,y) plane.
            </xhtml:p>
            <xhtml:p>
            After trying other methods, we finally settled on using a shooting method, in which "the closest approach" of a solution to
            its initial configuration is optimized for, until the difference between initial configuration and "closest approach" is
            numerically negligible, and the solution is an acceptable numerical approximation of a closed orbit.  We found an interesting
            correspondence between rational numbers and classes of closed Kepler-Heisenberg orbits.
            </xhtml:p>
            <xhtml:p>
            Part of this research project was done while Corey and I were in residence at <xhtml:a href='https://www.msri.org/'>MSRI</xhtml:a>
            during their summer research program, which was immensely enjoyable.
            </xhtml:p>
            <xhtml:p>
            We published all the code used to generate the results of the paper as free, open-source software at
            <xhtml:a href='https://github.com/vdods/heisenberg'>https://github.com/vdods/heisenberg</xhtml:a>.  There are detailed
            instructions given there, including a a single command that will replicate all the results (at the time of publication,
            it took 10 hours to run on my laptop).
            </xhtml:p>
            <xhtml:p>
            <xhtml:a href='https://doi.org/10.1080/10586458.2017.1416709'>Article link</xhtml:a>,
            <xhtml:a href='papers/2017-num-methods-closed-orbits-kepler-heisenberg--published.pdf'>Paper</xhtml:a>,
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Geodesic Trajectories On Regular Polyhedra</name>
        <short-description>with Diana Davis, Jed Yang, and Cindy Traub</short-description>
        <years>2012-2016</years>
        <description>
            <xhtml:p>
            <xhtml:a href='papers/2016-geodesics-on-the-regular-tetrahedron-and-the-cube.pdf'>This paper</xhtml:a>
            (<xhtml:a href='http://arxiv.org/abs/1508.03546'>preprint</xhtml:a>) was the result of a collaboration which started at the
            <xhtml:a href='http://www.ams.org/programs/research-communities/mrc-12'>2012 MRC Conference on Discrete and Computational Geometry</xhtml:a>.
            The purpose of the conference was to introduce a large group of near-PhD grads (mathematicians who were within 1 year of receiving
            their PhD) to the fields of discrete and computational geometry, and facilitate participation in those fields by having them
            work actively in groups on real problems.  The group I was a part of chose to work on included Jed Yang, Diana Davis, and Cindy Traub
            (among others) analyzing geodesics on polyhedra.  A year later, Diana, Jed, and I met up in Providence, Rhode Island to continue
            our research, and made significant progress on the problem.  Finally, Jed and Diana met up in 2015 to finish the work, we submitted
            it, and it was <xhtml:a href='https://www.sciencedirect.com/science/article/pii/S0012365X16302254'>it was published in 2016</xhtml:a>.
            </xhtml:p>
            <xhtml:p>
            The collaboration was fun and engaging, and involved use of a wide range of disciplines.  I really enjoyed the opportunities
            that the MRC conference provided, and I hope they continue to organize such conferences well into the future.
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>What Happens When You Push A Cubic Meter Of Jello Into A Wormhole?</name>
        <short-description>PhD dissertation</short-description>
        <years>2011-2013</years>
        <description>
            <xhtml:p>
            This work, and in fact my entering a grad program in math, was largely motivated by the visualization of curved space
            idea and project started in my undergrad.  While the ray-tracing involved in visualizing curved space is a rather
            straightforward problem (your space is a Riemannian manifold and your 'straight lines' are geodesics), there is a
            more subtle problem in that because the space is curved, physical objects within that space must deform from what
            one would intuitively think of as their 'rest configuration' in order to inhabit that space.  Such an embedded
            object would undergo internal stresses caused by the curvature of the space itself.
            </xhtml:p>
            <xhtml:p>
            The problem is that there are an infinite number of ways to embed any given object (say, an artist-created model of a
            spaceship) into a manifold (think of embedding an infinitely strechable ball into a curved space), but these embeddings
            don't in general respect any sort of solid-body deformation physics.  An arbitrary embedding would be physically meaningless.
            This is precisely the problem suffered by my previous projects; I embedded physical objects modeled in flat 3-space
            (e.g. a lamp, a table, etc) into the curved space via their coordinate charts, and so their deformations depend on the
            coordinate charts, and not on the properties of the objects themselves.
            </xhtml:p>
            <xhtml:p>
            My dissertation chooses elastic mechanics as the model for deformable solid bodies, discusses some of the existing theory,
            and then develops it in the setting of Riemannian manifolds (curved spaces in which distances can be measured).
            A few particular example problems are worked out in detail, and the tools to work out more general problems are
            presented.  The entirety of my work Riemannian Calculus of Variations using Strongly Typed Tensor Calculus is included
            as a necessary foundation for the calculations done in the specific problems.
            </xhtml:p>
            <xhtml:p>
            <xhtml:a href='papers/20131207-victor-dods-phd-thesis.pdf'>What Happens When You Push A Cubic Meter Of Jello Into A Wormhole?</xhtml:a>
            </xhtml:p>
            <xhtml:p>
            After passing the qualifying exams, Professor Richard Montgomery asked me to be his PhD student, working on the 4 body problem of
            orbital dynamics -- a problem that is of interest to many.  The 3 body problem has a very old pedigree, dating back to
            Newton, and is a problem that Richard had made significant contributions to.  While it was interesting and I learned a lot
            in pursuit of that topic, at some point I re-realized that I had come to grad school to work on the particular problem
            of the mechanics of objects in curved space.  Richard felt that he wouldn't be an appropriate advisor for me on the problem,
            so I talked to Debra Lewis, who had done research in relevant areas of geometric mechanics, and she agreed to advise me
            working on my problem.  I'm grateful to her for her patience and guidance in that.
            </xhtml:p>
            <xhtml:p>
            At some point later (certainly by the 2015 GMC Summer School at La Cristalera) I realized that academic math is a social
            activity, and that by picking my own problem and not doing the legwork of integrating it into a mathematical community
            and getting others interested in it, I somewhat put myself in an academic vacuum which would not have happened had I
            stayed working on the 4 body problem of orbital dynamics for which there was already an active community of interested
            people.  I don't regret this choice, because it was (and still is) a deep-seeded need to pursue this particular problem
            to a useful and concrete conclusion (e.g. real-time, interactive curved-space rendering and elastic mechanics, perhaps
            in the form of a game).  I'm perfectly happy working on things entirely alone, but realize that participating in a
            community is probably more conducive to quicker progress and inclusion in serious research efforts that couldn't
            necessarily be done by a single person.
            </xhtml:p>
        </description>
      </subcategory>
    </subcategories>
  </category>
  <category>
    <title>Earlier/less-formal academic math work</title>
    <subcategories>
      <subcategory>
        <name>Visualization Of The Effects Of Curved Space</name>
        <short-description></short-description>
        <years>2003</years>
        <description>
            <xhtml:p>
            A paper written for my senior seminar project at UCSC.  The program implementation (whose source code was
            lost in a hard drive failure) was the predecessor to Einstein's Eye (an infinitely better program).
            </xhtml:p>
            <xhtml:p>
            <xhtml:code><xhtml:a href='papers/visualization_of_the_effects_of_curved_space.pdf'>visualization_of_the_effects_of_curved_space.pdf</xhtml:a></xhtml:code>
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Rigid Body Collisions</name>
        <short-description></short-description>
        <years>2004-2005</years>
        <description>
            <xhtml:p>
            Deriving the math behind rigid-body collision response (impulse-based change of velocities).  I did this
            before grad school, and my skill in linear algebra and mathematical writing has drastically improved since
            then.  I may rewrite this paper at some point with my newly gained powers of mechanics.
            </xhtml:p>
            <xhtml:p>
            <xhtml:code><xhtml:a href='papers/rigid_body_collision.pdf'>rigid_body_collision.pdf</xhtml:a></xhtml:code>
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Understanding Real Derivatives Of Complex-Valued Maps</name>
        <short-description></short-description>
        <years>2010</years>
        <description>
            <xhtml:p>
            After slogging through countless tangent map calculations (i.e. multivariable derivatives in the vector
            calculus sense) involving maps that were inherently defined in terms of complex variables, I came up with
            a slightly more efficient means of computation.  While I'm sure it's by no means original mathematics (it's
            straightforward enough that an undergrad with a solid linear algebra, vector calculus and complex analysis
            background could provide proofs for the results presented here), I have not seen it in any book or article.
            </xhtml:p>
            <xhtml:p>
            I presented this material at a differential geometry seminar at UCSC, Spring quarter 2010, held by Wyatt Howard,
            Corey Shanbrom and me.  I presented it for the graduate colloquium series at UCSC during Fall quarter 2010, and
            then again for the undergraduate colloquium series at UCSC during Winter quarter 2011.
            </xhtml:p>
            <xhtml:p>
            <xhtml:code><xhtml:a href='papers/derivatives_of_complex_maps.pdf'>derivatives_of_complex_maps.pdf</xhtml:a></xhtml:code>
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Tensor Heaven</name>
        <short-description>mini-textbook on strongly typed tensor formalism in linear algebra</short-description>
        <years>2012</years>
        <description>
            <xhtml:p>
            The use of tensor objects (in the form of tensor fields) is ubitquitous in differential geometry (e.g. curvature
            tensors, general relativity, continuum mechanics), and therefore expertise in their use is critical.  Over probably
            a two-year period starting in 2010, I began working with tensors and tensor fields in a way which uses the notion
            of "strongy typed" language (borrowed from computer science) to formulate a robust technique for doing tensor
            calculations.  In it, the "type" of an object is used to explicitly express which constructions and operations are
            allowed, using only the natural pairing on a vector space or vector bundle.  Errors resulting from inherent
            misusage of the objects are readily detected.  Furthermore, the meaning of objects or means of their usage can
            often be inferred from their type.  This exposition is an introduction to the linear-algebraic formulation.  There
            will be more to come, specifically targeted at tensor calculus, in which the notion of a "pullback bundle" further
            enriches the type system used within.
            </xhtml:p>
            <xhtml:p>
            I presented this material at the Graduate Colloquium Series at UCSC, Spring quarter 2012.
            </xhtml:p>
            <xhtml:p>
            <xhtml:code><xhtml:a href='papers/20120405-tensor-heaven.pdf'>20120405-tensor-heaven.pdf</xhtml:a></xhtml:code>
            </xhtml:p>
        </description>
      </subcategory>
    </subcategories>
  </category>
  <category>
    <title>Old job projects</title>
    <subcategories>
      <subcategory>
        <name>Medal Of Honor: Pacific Assault</name>
        <short-description></short-description>
        <years>2003-2005</years>
        <description>
            <xhtml:p>
            TKO Software (now defunct) was contracted by Electronic Arts to implement the multiplayer mode of
            <xhtml:a href='http://en.wikipedia.org/wiki/Tommy_Conlin_%28MOHPA%29'>Medal of Honor: Pacific Assault</xhtml:a>
            (MOHPA - or as we sometimes called it, PacAss).  The MOH engine at that point had a long pedigree consisting of
            Quake 3 Arena, Heavy Metal FAKK 2, MOH Allied Assault, and MOH Breakthrough (there might be another in there I'm forgetting).
            Pure C code up though MOHBT, the MOHPA engine brought skin-grafts of C++ and by that point was getting to be a
            heaping monstrosity. Much of the emphasis of MOHPA was on the looks of the game (and it did look great) - a
            persistent mouse-lag problem was symptomatic of this.
            </xhtml:p>
            <xhtml:p>
            The multiplayer game development started off with a prototype of the "invader" gametype (similar to the "assault"
            gametype in Unreal Tournament 2004) in the MOHBT engine.  The MOHBT engine was efficient and responsive, the maps
            cannibalized for prototyping were compact and hectic, and the development experience at that point was a lot of
            playtesting and game tuning fun.  In particular, I had created a map script to control a massive blast door on the
            front of a tunnel, which made for some very fun (and hilarious) gameplay.  Players could push on either side of
            it, with more players equating to more force.  Jeff Zaring (a designer at TKO) added "murder holes" to the blast
            door for extra carnage.  The tunnel/door map was a prototype for what eventually became the Corregidor map, though
            the blast door game element was not included.  In general, the tuned gameplay mechanics we developed during
            prototyping the invader gametype were not used in the final game.  The objectives became generic "blow this wall
            up", "activate this radio", "destroy this thingy" missions, spread out over gigantic maps, which left players
            running to catch up most of the time.  The close-quarters prototype maps were much more fun. While the gameplay
            wasn't special, the game looked great.  And that's obviously all that really matters.
            </xhtml:p>
            <xhtml:div class='image-box'>
                <xhtml:center><xhtml:a href='tko_ownage.jpg' target='_blank'><xhtml:img src='thumbnails/tko_ownage.jpg'/></xhtml:a></xhtml:center>
                <xhtml:div class='caption'>
                    Results of one of the playtest games held during the month-long deathmarch at EA's LA headquarters (EALA).
                    A lot of the playtesters involved in MOHPA were based in EA's Redwood Shores office (EARS).
                </xhtml:div>
            </xhtml:div>
            <xhtml:p>
            I did a significant portion of the multiplayer map scripting (the MOH scripting language has some really cool
            features such as multi-threading, but is terribly finnicky in practice), worked on some of the engine network code,
            worked on getting the (existing) ragdoll physics working in multiplayer (a monumental pain in the ass) and
            probably most prominently, designed and implemented the multiplayer scoreboard (see right).
            </xhtml:p>
            <xhtml:p>
            There was a persistent and hilarious bug in the ragdoll physics where when you'd kill another player, he would end
            up standing up (at first it was in the animator's "jesus pose", then later in the "i'm aiming my gun" pose).  This
            phenomenon was termed "VERTICORPSE".  Eventually, in playtesting, we started ignoring players that were standing
            still, assuming they were verticorpses.  Eventually, we learned to stand still to mimic a verticorpse and therefore
            be ignored.  Eventually, we learned to shoot everyone, no matter how verticorpsey they looked.  My favorite part
            of the final product multiplayer game was the simple pleasure of stabbing people in the face with the bayonet.
            </xhtml:p>
            <xhtml:p>
            Toward the end of the project, for what ended up being the entire month of October 2004, the whole MOHPA team at
            TKO Software (based in Santa Cruz) was shipped down to EA's Los Angeles headquarters so we could work 12-14 hour
            days under the watchful eye of the EA execs.  This was completely uncalled for, as there was nothing we could do
            in LA that we couldn't do in Santa Cruz.  Furthermore, it torpedoed morale even more than normal crunch mode, as
            we were all away from our homes/families/friends, put up in some sterile corporate hotel-housing not too far from
            the office.  There were many loopy late nights, as my friend Nate Lieby can attest to.  So loopy, in fact, that we
            were considered disruptive, and separated so as not to cause any more circle-running, penny-snapping,
            hippopotamus-hippopotamus, old-man-double-voice ruckus.  Fortunately, Stu Fullmer and I continued the loopy times
            from our new desks, surrounded by EA engineers who I'm sure were delighted by our presence.
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>PUDL2 Compiler</name>
        <short-description>for a UI-control scripting language</short-description>
        <years>2006</years>
        <description>
            <xhtml:p>
            PUDL2 (Producer's Unified Description Language) was (is?*) a scriptable control system for the UI flow in the MCL (Media Control Library - Lightsurf's Picturemail library for Sprint phones).  The original PUDL was controlled by scripts which looked not unlike assembler code, and was very hard to read, write and maintain.  The second coming of PUDL (hence the 2) turned the control language into a full fledged C-syntax scripting language.
            </xhtml:p>
            <xhtml:p>
            Of course, this required writing a compiler, a task with which I was (gladly) charged - I like language theory and compilers (see BARF).  The Great And Venerable Ward Willats wrote the bytecode runtime (the thing which ended up running the compiled bytecode in the MCL itself) and did most of the language design. I contributed a little bit to the language design, for example 'switch' statement blocks defaulting to 'break', and requiring the 'continue' keyword to fall through as in C.
            </xhtml:p>
            <xhtml:p>
            The compiler took about a month to design and code.  The GNU tools <a href=''>bison</a> and <a href=''>flex</a> were used to generate the parser and scanner code respectively.  Integrating the code that these tools produced into a reentrant C++ program sucked total shit.  The generated code is overflowing with preprocessor macros and is hard to read.  Besides that annoyance, the PUDL2 compiler development went really smoothly.  Later in the MCL's development, coworkers would come to me claiming they had found a bug in the compiler.  Invariably it would turn out to be a bug in the MCL itself (ha ha!), which was great because it meant I had done some solid work.  On the other hand, it meant that I had to reason to have fun working on the compiler again. &lt;/vanity&gt;
            </xhtml:p>
            <xhtml:p>
            The crappy experience using bison and flex for parser/scanner development directly inspired the first version of trison, which led to the BARF project.
            </xhtml:p>
            <xhtml:p>
            * I'm not sure (though I doubt) if the MCL is still in active production.
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Touchless 1.0</name>
        <short-description>Windows/Mac service for OS interaction using the Leap Motion Controller</short-description>
        <years>2013</years>
        <description>
            <xhtml:p>
            <xhtml:a href='https://apps.leapmotion.com/apps/touchless-for-mac/osx'>Touchless</xhtml:a> was a project I
            worked on at Leap Motion which was an attempt at replacing the mouse/trackpad
            using the Leap Motion Controller (LMC) for general OS control.  This was at the time when Leap's
            intended target market was still consumer desktop, before VR was much of a thing.  This was also at the time
            when it wasn't yet understood that the LMC wasn't going to replace the mouse or keyboard -- they were
            difficult to compete with, what with having been refined over decades.  We found that while the Leap
            was very accurate in tracking hands and tools, it was difficult for a human user to control their hands
            and fingers in the air as precisely as a mouse on a solid surface could be controlled.  Also particularly
            difficult was interacting with an invisible 'virtual screen' plane -- the natural way people imagine using
            the LMC to click on buttons on a 2D screen was to poke their finger forward, miming poking a button imagined
            to be directly in front of their fingertip.  However, we found that this human-imagined screen didn't cleanly
            correspond to a fixed plane above the LMC, so even detecting a 'button poke' gesture proved to be rather involved.
            Put differently, 'intuitive/natural' human movements are more qualitative or symbolic in nature, whereas
            the input required for a GUI designed for the mouse demands quantitative precision.
            </xhtml:p>
            <xhtml:p>
            The work I did for this project was mostly creating the motion/gesture recognizer, largely in collaboration
            with my friend Ted Nitz.  We used a simple state machine to handle the context-dependent, gesture/motion-generated
            events (such as detecting a button poke start/end, starting/finishing a scroll, a swipe gesture, etc).  There
            was a lot of experimentation in which hand motions to use for various things.  One of the favorite features was
            'hover to drag' -- it was particularly easy and intuitive to use.  Dragging an icon around isn't a terribly
            common activity, so perhaps 'hover to click' would have been a better feature.  The swipe up/down/left/right
            features were chosen to be in direct correspondence with the Mac trackpad features, which were show/hide expose
            (up and/or down) and switch desktops (left/right); these worked particularly nicely.  This observation is
            what led me to make certain simple design decisions for Swipey Joe McDesktop (see project blurb below), which
            was based on a very small set of well-defined and robustly detectable gestures.
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Quick Switch</name>
        <short-description>Unity plugin for detecting a sentinel gesture used for switching out of VR apps</short-description>
        <years>2014</years>
        <description>
            <xhtml:p>
            The Leap Motion Controller (LMC) found a particularly nice double-use in virtual reality (VR), which provided a
            solid technical basis for the company to focus on VR.  In particular, we could mount a LMC on the front of a VR
            headset, and then have our actual hands appear within the VR environment, without the need for any clunky
            peripherals.  With the addition of the image passthrough feature to the Leap developer toolkit, we found that
            we automatically provided a bridge between VR and augmented reality (AR).  
            </xhtml:p>
            <xhtml:p>
            Before that point, a frequent obstacle was encountered with any VR development.  If the developer or user wanted
            to temporarily escape the VR environment and see the real world, s/he would have to take the whole headset off,
            which was a rather awkward thing to do.  With Leap's image passthrough feature, one could simply switch to the
            video feed coming from the Leap's two cameras, and have true binocular vision into the real world.  Because the
            development was focused on hand-based interaction, it was decided to create a particular sentinel gesture that
            wouldn't interfere with normal hand-based interaction.  In particular, it was to do an up/downward swipe with
            the edge of the palm across the LMC at a distance of 0-2 inches.  At this distance, the cameras couldn't see enough of the
            hands to track them, so there wouldn't be any hand tracking anyway.  Because of the lack of hand tracking at
            this distance, the solution had to be based on direct image processing.
            </xhtml:p>
            <xhtml:p>
            I wrote a simple image-based gesture recognizer which simply sampled the image in a particular, sparse lattice,
            combined the lattice's row values together in a particular way, and then essentially did blob tracking to
            determine if the gesture was happening and if so, quantifying its progress toward complete (so that realtime
            feedback could be used to indicate this gesture's activation).  With a bunch of tuning and some user testing
            and feedback, it was honed into a reasonably effective and robust gesture recognizer.
            </xhtml:p>
            <xhtml:p>
            This gesture recognizer was then incorporated into a Unity plugin called
            <xhtml:a href='http://blog.leapmotion.com/quick-switch-swipe-vr-real-world-unity/'>Quick Switch</xhtml:a>,
            which was used to switch between the Unity app and video passthrough, so that the user could quickly
            become aware of and interact with the real world without having to take the VR headset off.
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Swipey Joe McDesktop</name>
        <short-description>Python service generating keyboard events from gestures using the Leap Motion Controller</short-description>
        <years>2015</years>
        <description>
            <xhtml:p>
            Leap had an internal hackathon for which I created a simple Python service called
            <xhtml:a href='https://github.com/vdods/SwipeyJoeMcDesktop'>Swipey Joe McDesktop</xhtml:a> for recognizing a small set of
            well-defined and robustly detectable gestures.  The general scheme was that hand swipes in the 8 main
            compass directions (east, north-east, north, north-west, west, south-west, south, south-east) and finger
            taps were detected, and sequences of such gestures could be configured to generate keyboard events through
            the OS to do things like switch desktops, activate certain apps, or anything else you could set a keyboard
            shortcut for.  It was designed to be as simple and to the point as possible, with no UI or visual feedback
            or anything, though those features would be obvious for a V2, and would certainly improve the usability.
            The service is configured by editing a JSON-formatted text file.
            </xhtml:p>
            <xhtml:p>
            At the end of the hackathon, there were demos and a panel of judges picked winners in various categories --
            I won the 'most useful' category.
            </xhtml:p>
        </description>
      </subcategory>
    </subcategories>
  </category>
  <category>
    <title>Old projects</title>
    <subcategories>
      <subcategory>
        <name>Morph</name>
        <short-description>GUI-controlled image morphing program</short-description>
        <years>2002</years>
        <description>
            <xhtml:p>
            Done for Professor Alex Pang's CMPS 161 (computer graphics) at UCSC during Winter quarter of 2002, it used a clever and simple linear interpolation method to morph between two images with source/destination feature data supplied by the user.  There was a GUI (written in FLTK, the GUI toolkit of choice for the class) which allowed the user to specify pairs of oriented line segments on the source and destination images.  The source image data in a weighted neighborhood of each line segment would be interpolated with the weighted neighborhood of the corresponding line segment in the destination image data.
            </xhtml:p>
            <xhtml:p>
            The source code for this, as well as much of my other source code at the time, was lost in a hard drive failure in 2003 (boo, IBM deskstar harddrives).
            </xhtml:p>
            <xhtml:p>
            The original webpage made for the CMPS 161 assignment (on the right in the source and destination pictures is Mike Graben, a friend of mine who lost 100 pounds on the Atkins diet - I would have made this particular morph more detailed, but drawing the line segment pairs was a pain in the ass).
            </xhtml:p>
            <xhtml:p>
            <xhtml:a href='morph/morph.html' target='_blank'>Addendum to the Atkins Diet results</xhtml:a>
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Radiosity</name>
        <short-description>progressive radiosity lighting for 3D scenes</short-description>
        <years>2002</years>
        <description>
            <xhtml:p>
            Done for Professor Alex Pang's CMPS 260 (computer graphics) at UCSC during Spring quarter 2002, it modeled soft shadows and lighting in 3d scenes by determining light contributions from all visible sources (light sources and surfaces reflecting light), as opposed to the harsh point-light method of ray tracing.  It consisted of two passes: 1. form a matrix of light contribution ratios between all pairs of surfaces in the scene, 2. numerically approximate a steady-state solution for a system of ODEs formed from the matrix in the first part.  With a little OpenGL fanciness, part 1 could be done in hardware by rendering the scene from the perspective of each surface, recording the ratio of pixels visible from each other surface.  I just did it in software, so it was slow, but it would be something cool to try again one day.
            </xhtml:p>
            <xhtml:p>
            The source code for this, as well as much of my other source code at the time, was lost in a hard drive failure in 2003 (boo, IBM deskstar harddrives).
            </xhtml:p>
            <xhtml:p>
            Here are some images produced by the program (all the scene geometry was generated programmatically - I should have bothered to get some nice models for this).
            </xhtml:p>
            <xhtml:p>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='radiosity_00.jpg' target='_blank'><xhtml:img src='thumbnails/radiosity_00.jpg'/></xhtml:a>
                    <xhtml:a href='radiosity_01.jpg' target='_blank'><xhtml:img src='thumbnails/radiosity_01.jpg'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> One of the earlier images, with a low triangle-count and using only flat shading.  <xhtml:strong>Right:</xhtml:strong> The light is pure white and the colors are coming from the reflections of the colored balls.
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='radiosity_02.jpg' target='_blank'><xhtml:img src='thumbnails/radiosity_02.jpg'/></xhtml:a>
                    <xhtml:a href='radiosity_03.jpg' target='_blank'><xhtml:img src='thumbnails/radiosity_03.jpg'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> Another view of the previous scene.  <xhtml:strong>Right:</xhtml:strong> A single diamond-shaped surface emitting light (facing away) within a room with no ceiling, showing the reflection of light to areas of the room behind the diamond-shaped light.
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='radiosity_04.jpg' target='_blank'><xhtml:img src='thumbnails/radiosity_04.jpg'/></xhtml:a>
                    <xhtml:a href='radiosity_05.jpg' target='_blank'><xhtml:img src='thumbnails/radiosity_05.jpg'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> A pentagram casting two shadows from the red and yellow colored lights below.  <xhtml:strong>Right:</xhtml:strong> A grid of white spheres over a white floor showing the interplay of the colored lights above.
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='radiosity_06.jpg' target='_blank'><xhtml:img src='thumbnails/radiosity_06.jpg'/></xhtml:a>
                    <xhtml:a href='radiosity_07.jpg' target='_blank'><xhtml:img src='thumbnails/radiosity_07.jpg'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    Left and right: Two more views of the previous scene.
                </xhtml:div>
            </xhtml:div>
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Uthelleaux</name>
        <short-description>Othello game clone done in QT 2</short-description>
        <years>2002</years>
        <description>
            <xhtml:p>
            Uthelleaux is an Othello game implemented in <xhtml:a href='http://qt.nokia.com/'>Trolltech's QT toolkit</xhtml:a> version 2 (QT is by far the best GUI toolkit I've used.  The QT development tools are top notch, the library is solid, and the documentation is abundant).  There are several levels of AI (implemented using an minimax DFS algorithm (with alpha-beta pruning, if I recall correctly), which gives pretty decent performance and difficulty (though definitely beatable).
            </xhtml:p>
            <xhtml:p>
            Uthelleax 1.0 was written in MFC (for WIN32) and therefore sucked.  Plus it didn't have very difficult AI players.  I'm not sure if I even care if I have the source code.
            </xhtml:p>
            <xhtml:p>
            There is light-green highlighting to indicate valid moves, and holding the right mouse button on a square will give a preview of the result of that move.
            </xhtml:p>
            <xhtml:p>
            Since QT 2 is outdated, I haven't been able to compile Uthelleaux in several years.  It would be nice to someday port it to QT 4.
            </xhtml:p>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='uthelleaux-2.0-snap1.png' target='_blank'><xhtml:img src='thumbnails/uthelleaux-2.0-snap1.png'/></xhtml:a>
                    <xhtml:a href='uthelleaux-2.0-snap2.png' target='_blank'><xhtml:img src='thumbnails/uthelleaux-2.0-snap2.png'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> Beginning of the game.  <xhtml:strong>Right:</xhtml:strong> Menu for player type and/or AI difficulty.
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='uthelleaux-2.0-snap3.png' target='_blank'><xhtml:img src='thumbnails/uthelleaux-2.0-snap3.png'/></xhtml:a>
                    <xhtml:a href='uthelleaux-2.0-snap4.png' target='_blank'><xhtml:img src='thumbnails/uthelleaux-2.0-snap4.png'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> The legal play squares are highlighted.
                    <xhtml:strong>Right:</xhtml:strong> Game-over statistics.
                </xhtml:div>
            </xhtml:div>
            <xhtml:p>
            Uthelleaux is free open source software, released under the GNU GPL license.  Source code:
            </xhtml:p>
            <xhtml:p>
            <xhtml:code><xhtml:a href='uthelleaux-2.0.tar.bz2'>uthelleaux-2.0.tar.bz2</xhtml:a></xhtml:code>
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Antichess</name>
        <short-description>chess-based game in QT 2 and for web CGI</short-description>
        <years>2002</years>
        <description>
            <xhtml:div class='image-box'>
                <xhtml:center><xhtml:a href='antichess.png' target='_blank'><xhtml:img src='thumbnails/antichess.png'/></xhtml:a></xhtml:center>
                <xhtml:div class='caption'>
                    A screenshot of the QT version of Antichess, showing the selected piece (black king) and
                    all the pieces it threatens (the white queen).  The visual style was predicated on XBoard.
                </xhtml:div>
            </xhtml:div>
            <xhtml:p>
            Antichess was a game taught to me by my friend Danny Greenhouse.  An absurd variant of chess, the
            object is to be the first one to lose all your pieces.  The key rule is that if a player can take a
            piece, they must. If they can take more than one piece, they get the choice.  There are no other
            rules, except that the king is not special.
            </xhtml:p>
            <xhtml:p>
            I took two approaches to this game: a web CGI version (which is clunky by today's web 2.0 standards),
            and a GUI app (done in QT 2, just like Uthelleaux).
            </xhtml:p>
            <xhtml:p>
            The web version can be found <xhtml:a href='http://www.thedods.com/cgi-bin/antichess.cgi'>here</xhtml:a>,
            though is having problems with processing the commandline arguments it needs to run (but hey, the
            executable is literally 8 years old - it's amazing it still runs at all).  Each player must click on
            a piece to select it, then click on a square to move it.  The only thing I would have liked to have
            added is a little yellow box around a selected piece. This web CGI version of Antichess looks good,
            but is very primitive from a web development perspective.  In a way, it was an exercise to learn web CGI.
            </xhtml:p>
            <xhtml:p>
            The QT version was similar to Uthelleaux in design and style.  It included a computer player (not
            terribly difficult), and displayed the available moves and captures for the selected piece.  Like
            Uthelleaux, it uses a deprecated version of QT, so I haven't been able to run it in a while.  I'm
            thinking if I get terribly bored some day, I'll port it and Uthelleaux to QT 4, so they can live
            once again.
            </xhtml:p>
            <xhtml:p>
            Antichess is free open source software, released under the GNU GPL license.  Source code:
            </xhtml:p>
            <xhtml:p>
            <xhtml:code><xhtml:a href='antichess-0.9.2.tar.bz2'>antichess-0.9.2.tar.bz2</xhtml:a></xhtml:code>
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Quake 3 Arena maps</name>
        <short-description></short-description>
        <years>2003</years>
        <description>
            <xhtml:p>
            After first playing Q3A in 2000, I had joined the clan "Dynasty" in 2002 using the handle "Humiliation",
            which was what the game announcer said when a player was killed with the melee gauntlet weapon.  Dynasty
            started out as an instagib deathmatch clan (instagib is a railgun-only, one-shot-one-kill game mode),
            but soon got into instagib capture-the-flag (ICTF).  Eventually I tried my hand at designing some Q3A
            maps, mainly for ICTF, some of them actually being pretty fun team play maps.  One of the maps,
            <xhtml:code>dynasty-ctf4</xhtml:code>, was designed by James Majidian ("Impulse").
            </xhtml:p>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='dynasty-ctf1.jpg' target='_blank'><xhtml:img src='thumbnails/dynasty-ctf1.jpg'/></xhtml:a>
                    <xhtml:a href='dynasty-ctf2.jpg' target='_blank'><xhtml:img src='thumbnails/dynasty-ctf2.jpg'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> "King Of The Mountain" (<xhtml:code>dynasty-ctf1</xhtml:code>) was
                    simple and blocky, and a little too open for real instagib CTF matches, but made for some good rocket/trick
                    jumping.  <xhtml:strong>Right:</xhtml:strong> "Into The Fucking Pit!" (<xhtml:code>dynasty-ctf2</xhtml:code>)
                    was another blocky-design map with many pillars jutting out from a large pit in the center.  Players could
                    try to strafe jump over the pillars, or run some carefully guided lines along the sides.  The windows in
                    front of each flag would open when shot.
                </xhtml:div>
            </xhtml:div>
            <xhtml:p>
            The main design feature of these maps was the use of slick (as in ice) Bezier patches (curved surfaces).  These
            were used in portions of certain maps to give a skating dynamic to the maps.  Two of the maps resembled skate parks.
            </xhtml:p>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='dynasty-ctf3.jpg' target='_blank'><xhtml:img src='thumbnails/dynasty-ctf3.jpg'/></xhtml:a>
                    <xhtml:a href='dynasty-ctf5.jpg' target='_blank'><xhtml:img src='thumbnails/dynasty-ctf5.jpg'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> "Blood Bowl" (<xhtml:code>dynasty-ctf3</xhtml:code>) was probably the
                    best-looking and best-playing of the maps.  There was an "underground" area below the glass bowl players
                    could try to run through and lose pursuers.  Carefully done teamwork could allow players to grab the flag,
                    jump in the bowl and have their teammates boost them down into the bowl, shooting them out to the safety
                    of their home base.  Uncareful players would jump in the bowl, become stuck and get popped by the diligent
                    efforts of the railgun-toting defenders.  This is the best example of the simple aesthetic design maps I
                    made, where the only structural texture used was concrete, and everything else was done with lighting.
                    <xhtml:strong>Right:</xhtml:strong> "It's All In The Gravity" (<xhtml:code>dynasty-ctf5</xhtml:code>)
                    was the giant skate park map.  On the hardware of the era (e.g. a 1.4 Ghz machine), this map ran a little
                    slow, and was a little too big and open to be an effective map for competitive play, but was still fun
                    especially for rocket jumping.
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='dynasty-ctf6.jpg' target='_blank'><xhtml:img src='thumbnails/dynasty-ctf6.jpg'/></xhtml:a>
                    <xhtml:a href='dynasty-ctf7.jpg' target='_blank'><xhtml:img src='thumbnails/dynasty-ctf7.jpg'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> "Altar Of Sacrifice" (<xhtml:code>dynasty-ctf6</xhtml:code>) was the
                    most structurally detailed of the maps, and was more like a traditional Q3A map than the others.  Because
                    of its high level of detail, it ran a little slow in some areas (like the main altar room), but this didn't
                    seem to hinder the intense gameplay.
                    <xhtml:strong>Right:</xhtml:strong> "Skate... Or DIE!!!" (<xhtml:code>dynasty-ctf7</xhtml:code>)
                    was essentially a half-pipe with a few boosters providing some vertical to the dynamic.  Glass barriers
                    in front of the flags, over which players would have to jump to get to the safety of capture provided
                    many tense moments.
                </xhtml:div>
            </xhtml:div>
            <xhtml:p>
            The overall design aesthetic was simple/minimalistic, making heavy use of colored lights in place of geometric
            detail.  Another element I was sort of proud of was the addition of "iris doors" into <xhtml:code>dynasty-ctf5</xhtml:code>,
            which were visually and kinetically quite pleasing.  I never bothered to add weapons or powerups to the maps, since
            Dynasty was an instagib-only clan.  Unfortunately I lost all the map source files in a hard drive crash in 2003, and
            the <xhtml:code>q3map</xhtml:code> "bsp-to-map" conversion is far from perfect.
            </xhtml:p>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='dynasty-dm1.jpg' target='_blank'><xhtml:img src='thumbnails/dynasty-dm1.jpg'/></xhtml:a>
                    <xhtml:a href='dynasty-ctf8.jpg' target='_blank'><xhtml:img src='thumbnails/dynasty-ctf8.jpg'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> "Sumo Wrestling, Humiliation Style"(<xhtml:code>dynasty-dm1</xhtml:code>)
                    used a special configuration file.  It was based on sumo wrestling - players try to knock each other back
                    with the gauntlet weapon into the spikes at the edge of the ring.  The glass bowl is slick, just like in
                    <xhtml:code>dynasty-ctf3</xhtml:code>, and players gain points for staying within the ring, and lose points
                    for getting popped on the spikes.  Again, this map was pretty absurd, but super fun.
                    <xhtml:strong>Right:</xhtml:strong> "Newtonian Playground" (<xhtml:code>dynasty-ctf8</xhtml:code>) was predicated on
                    <xhtml:a href='http://q3a.ath.cx/?mapdetails=q3hockey'><xhtml:code>q3hockey</xhtml:code></xhtml:a> but was formed
                    into a giant, slick, ellipsoidal arena in which it was possible to be boosted by teammates up and around the curved
                    walls - this map was tiny and a little absurd, but extremely fun.
                </xhtml:div>
            </xhtml:div>
            <xhtml:p>
            The PK3 files are available here.  The <xhtml:code>dynasty-ctf1</xhtml:code> through <xhtml:code>dynasty-ctf7</xhtml:code>
            and <xhtml:code>dynasty-dm1</xhtml:code> maps are in the first file, <xhtml:code>dynasty-ctf8</xhtml:code> and the others
            are in the second.  Besides <xhtml:code>dynasty-ctf8</xhtml:code>, the "beta" pack file maps aren't particularly high
            quality.
            </xhtml:p>
            <xhtml:p>
            <xhtml:a href='dynasty-maps.pk3'><xhtml:code>dynasty-maps.pk3</xhtml:code></xhtml:a>
            </xhtml:p>
            <xhtml:p>
            <xhtml:a href='dynasty-maps2-beta.pk3'><xhtml:code>dynasty-maps2-beta.pk3</xhtml:code></xhtml:a>
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Rage</name>
        <short-description>Q3A mod</short-description>
        <years>2005-2007</years>
        <description>
            <xhtml:div class='image-box'>
                <xhtml:center><xhtml:img src='q3rage_logo.jpg'/></xhtml:center>
                <xhtml:div class='caption'>
                    A logo made for Rage by Clint Dunn ("Toad").
                </xhtml:div>
            </xhtml:div>
            <xhtml:p>
            At TKO Software, after finishing MOHPA, Nate Lieby and I did some prototype game development using the
            Quake 3 engine, designing and implementing a Robotron-2084-style game.  This involved a lot of really
            fun hacking, as game design and prototyping work is always the most enjoyable part of game development.
            The vanilla Q3 engine uses C and is designed in a very straightforward manner, making it easily modded.
            </xhtml:p>
            <xhtml:p>
            <xhtml:a href='http://en.wikipedia.org/wiki/Quake_III_Arena'>Quake 3 Arena</xhtml:a> (which was effectively
            ID's demonstration of their then new 3D game engine) operated on two levels - the engine code
            (which was proprietary at the time, though has since been
            <xhtml:a href='http://en.wikipedia.org/wiki/Id_Tech_3'>GPL'ed</xhtml:a>), and the moddable game code
            (game logic, weapons, GUI display, console commands, etc).  Both were written in C, though the client
            code was compiled into some sort of platform-independent bytecode by a separate compiler - the same mod
            files could be used on any of the supported platforms.  The moddable source code was freely available and
            really strengthened the Q3A community by encouraging player participation in the development of the game
            itself.  Two particularly well-done Q3A mods were
            <xhtml:a href='http://www.orangesmoothie.org/tourneyQ3A/'>OSP</xhtml:a> and
            <xhtml:a href='http://en.wikipedia.org/wiki/Threewave_Software'>Threewave</xhtml:a> (the Threewave mod
            came with many high-quality maps), each specifically geared towards tournament play.
            </xhtml:p>
            <xhtml:p>
            Rage was a Q3A mod I originally created to test out the technology and improve some of the details of
            vanilla Q3A I saw as lacking.  At first the changes were mainly cosmetic, such as spawning blood/guts
            (aka gibs) having the same momentum as the player when s/he died (in vanilla Q3A, the gibs would spawn
            from a fixed point in space, which looked wrong if the player was moving quickly).  Later, gameplay
            features were added, such as different scoring mechanics (see the feature list below under "different
            deathmatch scoring types").  A few of the more hilarious features added were the ability to scream
            at the touch of a button (using your character's death scream), the ability to spawn gibs at the touch
            of a button, and weapon heads (the model for your currently equipped weapon would be used as your head).
            The "main" feature of Rage ended up being the addition of 6 more teams for multiplayer gametypes (in
            colors matching that of the colorized console text).  To get the deathmatch and team deathmatch modes
            working was relatively easy.  The capture-the-flag (CTF) gametype took considerably more effort, and while
            functional, was never completed to a fully polished quality.  Additionally, the multi-team CTF gametype
            required customized maps having a base for each participating team.
            <xhtml:a href='http://planetquake.gamespy.com/View.php?view=MOTW.Detail&amp;id=183'>TribalCTF</xhtml:a> was
            another Q3A mod made specifically for 3-team CTF, and whose beautifully-done (though polygon-intensive
            and therefore relatively slow-running) maps could be used in Rage.
            </xhtml:p>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='rage_weaponheads.jpg' target='_blank'><xhtml:img src='thumbnails/rage_weaponheads.jpg'/></xhtml:a>
                    <xhtml:a href='rage_tdmgib.jpg' target='_blank'><xhtml:img src='thumbnails/rage_tdmgib.jpg'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> Setting the cvar <xhtml:code>cg_weaponheads</xhtml:code> to <xhtml:code>1</xhtml:code>
                    enabled weaponheads, where the currently equipped weapon model would be used in place of each player's head.
                    <xhtml:strong>Right:</xhtml:strong> Lots of things were colorized (blood/gibs, teams, railgun trails,
                    quaddamage aura), some of them being configurable.  Also the number of gibs spawn when a body was popped
                    was configurable.
                </xhtml:div>
            </xhtml:div>
            <xhtml:p>
            After a year or so of development hiatus for Rage, talking with fellow Q3A players Brian Vitko ("DeadArcher")
            and Clint Dunn ("Toad") got interest going again.  We decided to team up to develop Rage into a polished mod.
            While never originally intended to replace one of the major mods, we decided our goal would be to make a
            fork of the OSP Q3A mod (which had long ceased active development, though was still widely used).  I
            contacted the OSP guys, asking if I could have the (proprietarily-kept) source code to continue its
            development, merging it with the Rage codebase in the process.  While I did get the buy-off from one of
            the creators, I never heard back from the second guy, so it unfortunately never happened.  This effectively
            stopped development, as bringing Rage to the quality of a full mod would have been too great.  Before that
            happened though, we did manage to augment a few of the standard Q3A CTF maps (and a couple Threewave CTF
            maps) to use multiple teams (cutting apart the map geometry and pasting it together with a 3 or 4-fold
            symmetry instead of the usual 2-fold symmetry).  Radiant (the map editor used by Q3A) was unfortunately
            not designed to handle perfect 3-fold symmetry well (one couldn't duplicate parts of the map rotated by
            120 degrees without many map leak and visibility headaches).
            </xhtml:p>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='rage_multiteam.jpg' target='_blank'><xhtml:img src='thumbnails/rage_multiteam.jpg'/></xhtml:a>
                    <xhtml:a href='rage_ctfscore.jpg' target='_blank'><xhtml:img src='thumbnails/rage_ctfscore.jpg'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> The team deathmatch scoreboard for a 4-team game.  I didn't get a
                    chance to make a nice scoreboard before development halted.
                    <xhtml:strong>Right:</xhtml:strong> Showing a capture of two flags at once on the
                    <xhtml:code>ragectf1</xhtml:code> map.
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='ragectf1.jpg' target='_blank'><xhtml:img src='thumbnails/ragectf1.jpg'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:code>ragectf1</xhtml:code> was a modified version of <xhtml:code>q3ctf4</xhtml:code> made by
                    Brian Vitko ("DeadArcher"), having bases for 4 CTF teams.  Players could pick up and return multiple enemy
                    flags, while the flashing aura around the flag carrier would give additional indicators as to  which flags
                    were being carried.
                </xhtml:div>
            </xhtml:div>
            <xhtml:p>
            The work on Rage was very easy and enjoyable, and I really wish we had the time to bring it to the polished
            level of an OSP or Threewave (of course, I make the same time-wish about everything I do).  I was really
            hoping that Quake 4 multiplayer would turn out as good as or better than Q3A, but was sadly disappointed.
            While Raven (the studio contracted by ID to make Q4) clearly made an effort to duplicate the physics and
            gameplay of Q3A, there was just something lacking.  Hopefully Quake 5 will redeem the series :)
            </xhtml:p>
            <xhtml:p>
            The feature list included with the mod read as follows:
            <xhtml:ul>
                <xhtml:li>6 new teams for a total of 8 teams in team game types.  4 times the teams means 4 times the violence (CTF still in initial implementation stages).</xhtml:li>
                <xhtml:li>Customizable number of gibs.  Want more gratuitous gore?  Crank cg_gibs up to 50 and let the blood rain (while listening to SLAYER, of course).</xhtml:li>
                <xhtml:li>Client-side correction of body-gibbing momentum (gibs preserve the body's momentum).</xhtml:li>
                <xhtml:li>User-selectable coloring of blood and gibs.  The colors available are the same as the text colors (starting with 0: black, red, green, yellow, blue, cyan, purple and white).</xhtml:li>
                <xhtml:li>Death-rattle corpses: Instead of blandly sinking into the ground, ungibbed corpses will enter a death rattle and explode, doing radius damage.  Kill your friends from beyond the grave with your own corpse.  This defaults to off, but is highly configurable.</xhtml:li>
                <xhtml:li>Customizable weapon damage values for all of the standard q3 weapons.</xhtml:li>
                <xhtml:li>Configurable weapon cycle times (time it takes to fire 1 round).  Spam your friends with rockets and grenades.</xhtml:li>
                <xhtml:li>Configurable run speed factors per weapon.</xhtml:li>
                <xhtml:li>Cvar-controlled spread factors on the machinegun and shotgun.</xhtml:li>
                <xhtml:li>Controllable number of shotgun pellets.</xhtml:li>
                <xhtml:li>Railgun slugs can hit a cvar-controlled number of people (no longer capped at 4).  See if you can get your friends to line up so you can get a 15-fer.</xhtml:li>
                <xhtml:li>Flags retain the momentum of the carrier when they're dropped for more realistic motion.</xhtml:li>
                <xhtml:li>Self-damage is toggleable for your rocket jumping, plasma climbing and grenade hopping pleasure.</xhtml:li>
                <xhtml:li>Drowning damage is toggleable, for your hiding-under-water pleasure.</xhtml:li>
                <xhtml:li>Fake gibbing.  Freak out your friends by spewing gibs without dying.</xhtml:li>
                <xhtml:li>Screaming - trick your friends and enemies into thinking you've snuffed it by screaming your falling or death sounds.</xhtml:li>
                <xhtml:li>Gravity now works on everything correctly (players, grenades, etc).</xhtml:li>
                <xhtml:li>Vampire mode - when you damage other players, you gain health, configurable by cvars.</xhtml:li>
                <xhtml:li>Controllable weapon loadout.</xhtml:li>
                <xhtml:li>Controllable starting weapon.</xhtml:li>
                <xhtml:li>Controllable ammo ammounts (including -1 for infinite).</xhtml:li>
                <xhtml:li>CTF flag throwing.  Play keep away from your least popular friend.</xhtml:li>
                <xhtml:li>Players now gib upon disconnecting (which includes if they're kicked).</xhtml:li>
                <xhtml:li>Client-side help command.  /cg_help</xhtml:li>
                <xhtml:li>Different deathmatch scoring types: <xhtml:ul>
                    <xhtml:li>0: standard deathmatch</xhtml:li>
                    <xhtml:li>1: getting killed resets your score (winning streak scoring)</xhtml:li>
                    <xhtml:li>2: getting killed lowers your score by 1 (net kills scoring)</xhtml:li>
                    </xhtml:ul> </xhtml:li>
                <xhtml:li>Detailed weapon statistics.  Annoy your friends with how high your fucking railgun accuracy is.</xhtml:li>
                <xhtml:li>WEAPON HEADS!  YAY!</xhtml:li>
                <xhtml:li>Suicides can now be configured to credit the last person who attacked you.</xhtml:li>
                <xhtml:li>Catch-all weapon/health/armor/ammo/powerup/holdable disabling (in addition to the existing, verbose disabling cvars).</xhtml:li>
                <xhtml:li>Teammates/enemies have different spawning/teleporting sounds.</xhtml:li>
                <xhtml:li>Configurable maximum health, start health, equilibrium health, and start armor.</xhtml:li>
                <xhtml:li>Configurable respawn wait time.</xhtml:li>
                <xhtml:li>Weapon dropping when dead can be turned off.</xhtml:li>
                </xhtml:ul>
            </xhtml:p>
        </description>
      </subcategory>
    </subcategories>
  </category>
  <category>
    <title>Ancient projects</title>
    <subcategories>
      <subcategory>
        <name>DOS graphics programming</name>
        <short-description></short-description>
        <years>1993-1997</years>
        <description>
            <xhtml:p>
            I originally got into computer programming because of games - specifically, figuring out how to cheat
            at games by using a DOS hex editor; changing scores, experience points, and even character dialog.
            Eventually programming seized me at age 13, starting with QBASIC.  Regrettably all my BASIC source code,
            including the source code to a rather impressive (for a kid) graphical analog clock program I wrote,
            has been lost to the void of byte-oblivion.  The entire screen cleared and repainted once a second to
            update the clock hands, as I had no idea what a backbuffer was at that point.  This was 1993, at the
            height of BBSes, and right before the web was really known.<xhtml:br/>
            </xhtml:p>
            <xhtml:p>
            Eventually my mom bought me a book on Turbo Pascal, saying that it'll eventually help me earn lots of money,
            which is good seeing as I'll be supporting her some day.  I had also got my hands on the first version of
            the <xhtml:a href='http://www.reocities.com/SiliconValley/2151/pcgpe.html'>PCGPE</xhtml:a>, which got me
            started on VGA video mode coding (320x200 resolution, 256 paletted colors), which relied heavily on
            assembler programming.  "Denthor of Asphyxia"'s tutorials were notably helpful.  Between 1994 and 1995,
            I had begun to create some somewhat decent video demos, including some rudimentary 3D wireframe rendering
            programs.  Pascal was a much richer language than BASIC, especially when coupled with its inline assembler
            mode.  This type of programming is no longer exactly possible in modern operating systems, due to the
            safety of unprivileged execution modes and sanctioning system calls in order to do anything privileged
            (like access the hardware directly).  Unfortunately, all my Pascal source code has gone to Pascal heaven.<xhtml:br/>
            </xhtml:p>
            <xhtml:p>
            In 1996, I took a C programming course at Diablo Valley College (the local junior college) with my friend
            Danny Greenhouse.  While absurdly easy, the class was certainly productive and did help formalize some of
            my programming.  The use of pointers and structures (as opposed to Pascal's "records") make C a very powerful
            language - the Linux kernel is written in C, for example.  Turbo C++ 3.0 was the compiler of choice.  Like
            Turbo Pascal, Turbo C++ supported inline assembler code, so much of the knowledge and experience I had from
            writing inline assembler code in Pascal programs carried over.  I kind of miss the whole DOS development
            experience - using a text mode editor with its simple but attractive syntax highlighting and equally simple
            user interfaces with programmer efficiency in mind, the programmer bothering to spend time writing assembler
            code, instruction by instruction. I even miss the DOS console font and the 16 ANSI colors.<xhtml:br/>
            </xhtml:p>
            <xhtml:p>
            I kept doing DOS graphics programming, and getting a little bit into sound coding.  In 2009, to my
            unbounded delight, I recovered the data off of an old hard drive which had all of my old C source code, as
            well as my copy of TC3.  Most of the programs were dated 1997, "by chainsaw", which was my BBS handle back
            then.  I was ecstatic, because that meant I could actually run TC3 again (this time in DosBox) and compile
            and run my old programs.  If I had an absurd amount of free time, I would consider even doing more DOS
            programming in TC3 within DosBox.  Some of the programs didn't run properly, possibly from bugs in DosBox
            (the real DOS was relatively easy to crash anyway).  Many of the programs did run, and I went through as
            many as I could, taking screenshots.  I would like to take video of some of them to capture the animation
            (especially for the fire demo).<xhtml:br/>
            </xhtml:p>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='dos_bolt.png' target='_blank'><xhtml:img src='thumbnails/dos_bolt.png'/></xhtml:a>
                    <xhtml:a href='dos_dots.png' target='_blank'><xhtml:img src='thumbnails/dos_dots.png'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> "Bolt" - a lightning bolt demo program could run at high framerates
                    (DosBox clocked in at above 60 FPS, and judging by the performance of other DOS games within DosBox,
                    this is approximately the performance of an actual 486 system).  <xhtml:strong>Right:</xhtml:strong>
                    "Dots" - one of several 3D programs, this one rendered sprites for each of the point-masses in the
                    rotating model.  The sprites' on-screen sizes were scaled depending on how distant they were in the 3D scene.
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='dos_duck.png' target='_blank'><xhtml:img src='thumbnails/dos_duck.png'/></xhtml:a>
                    <xhtml:a href='dos_fire.png' target='_blank'><xhtml:img src='thumbnails/dos_fire.png'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> "Duck" - this demo is the one I was most proud of - a 3D polygonal
                    graphics engine with flat shading.  The face-ordering algorithm was slightly incorrect, causing some
                    distant polygons to be rendered in front of nearby polygons. This demo ran at 12-15 FPS on a 486
                    100Mhz machine, so it wasn't quite as visually pleasing.  The duck spun around wildly changing axes.
                    <xhtml:strong>Right:</xhtml:strong> "Fire" - The obligatory fire demo.  The algorithm was quite
                    clever and simple (gleaned from PCPGE as mentioned above), and ran fast - I believe 40 FPS in DosBox.
                    I would like to have this exact demo as a screensaver (complete with blocky resolution graphics).
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='dos_pottersfield.png' target='_blank'><xhtml:img src='thumbnails/dos_pottersfield.png'/></xhtml:a>
                    <xhtml:a href='dos_texturemap.png' target='_blank'><xhtml:img src='thumbnails/dos_texturemap.png'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> "Potter's Field" - this was a demo I made for my friend Erik Fong's
                    BBS "Potter's Field".  This demo was predicated on the "duck" demo shown above - the logo spun around.
                    I had also added sounds of Beavis and Butthead laughing at random intervals, though when I compiled and
                    ran it in DosBox, the sounds came through as complete garbage.  <xhtml:strong>Right:</xhtml:strong>
                    "Texture Map" - one of the more intricate routines I had written was a texture mapper.  It ran really
                    slow, but it looked pretty decent.  Just having done it was enough for me though.
                </xhtml:div>
            </xhtml:div>
            <xhtml:p>
            Here is some of the <xhtml:a href='dos_days.zip'>source code</xhtml:a> - specifically for "Duck" and "Fire".
            The code organization is utterly retarded compared to professional work - I even included <xhtml:strong>C files</xhtml:strong> for fuck's
            sake - but who cares, I was a kid :)
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Fracture</name>
        <short-description>GUI-based fractal exploring/generating app done in MFC</short-description>
        <years>1998</years>
        <description>
            <xhtml:p>
            Made using MFC after taking a class at Diablo Valley College in C++ GUI programming, Fracture was a fractal image
            exploring and generating program for <xhtml:a href='http://en.wikipedia.org/wiki/Mandelbrot_set' target='_blank'>Mandelbrot</xhtml:a>
            and <xhtml:a href='http://en.wikipedia.org/wiki/Julia_set' target='_blank'>Julia</xhtml:a> type fractals.
            </xhtml:p>
            <xhtml:p>
            It had a nice color gradient editor for creating detailed colorings to apply to the fractal shading.  In general,
            the most basic style of rendering assigns each pixel a color based on the number of iterations required to determine
            if a point in the complex plane is not in the set (and usually black if the point lies in the set).  This gives
            a visually discrete coloring pattern (see <xhtml:a href='http://en.wikipedia.org/wiki/File:Escape_Time_Algorithm.png' target='_blank'>this</xhtml:a>
            for an excellent example from Wikipedia).  At some point, I had Fracture performing smoothing to make the fractal
            coloring appear continuous (see <xhtml:a href='http://en.wikipedia.org/wiki/File:Normalized_Iteration_Count_Algorithm.png' target='_blank'>this</xhtml:a>
            for the corresponding smoothed Wikipedia example), but it looks like I took it out in later versions.
            </xhtml:p>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='RGB_mandel.png' target='_blank'><xhtml:img src='thumbnails/RGB_mandel.png'/></xhtml:a>
                    <xhtml:a href='blue_julia.png' target='_blank'><xhtml:img src='thumbnails/blue_julia.png'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> A red-green-blue gradient colored portion of the Mandelbrot set.
                    <xhtml:strong>Right:</xhtml:strong> A zoomed out image of a particular Julia set.
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='brown_mandel.png' target='_blank'><xhtml:img src='thumbnails/brown_mandel.png'/></xhtml:a>
                    <xhtml:a href='fluorescent_mandel.png' target='_blank'><xhtml:img src='thumbnails/fluorescent_mandel.png'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    Various color schemes on various portions of the Mandelbrot set.  I have a 2 by 3 foot printout of the
                    fluorescently colored one hanging above my desk in the UCSC math office.
                </xhtml:div>
            </xhtml:div>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='green_spirals.png' target='_blank'><xhtml:img src='thumbnails/green_spirals.png'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    Found by my friend Danny Greenhouse, this is my favorite image.  It shows a high degree of very pleasing
                    self-similarity. This one is also hanging above my desk in the UCSC math office.
                </xhtml:div>
            </xhtml:div>
            <xhtml:p>
            Unfortunately, Fracture uses MFC, and Visual Studio Express (the free version) doesn't come with MFC.
            I've been too lazy to find and install my old copy of Visual Studio 6, so no screenshots of the application
            itself in action (for now).  Plus, I loathe the entire Windows development experience, so I'm not particularly
            motivated to get that development environment running again.  Hopefully, the source code compiles as-is.
            </xhtml:p>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='fracture_00.png' target='_blank'><xhtml:img src='thumbnails/fracture_00.png'/></xhtml:a>
                    <xhtml:a href='fracture_01.png' target='_blank'><xhtml:img src='thumbnails/fracture_01.png'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    <xhtml:strong>Left:</xhtml:strong> Fracture in action, at the main exploration screen.  The exploration
                    screen uses a low-resolution preview to save computational time.  High-quality images can be created
                    via the "render" menu.
                    <xhtml:strong>Right:</xhtml:strong> The gradient-editing dialog.
                </xhtml:div>
            </xhtml:div>
            <xhtml:p>
            Fracture is free open source software, released under the GNU GPL license.  Source code:
            </xhtml:p>
            <xhtml:p>
            <xhtml:code><xhtml:a href='fracture.zip'>fracture.zip</xhtml:a></xhtml:code>
            </xhtml:p>
        </description>
      </subcategory>
    </subcategories>
  </category>
  <category>
    <title>Misc/small stuff</title>
    <subcategories>
      <subcategory>
        <name>Histogram</name>
        <short-description>text-based histogram generator</short-description>
        <years>2004</years>
        <description>
            <xhtml:p>
            Histogram was a tiny little C program I wrote when I needed to analyze some data.  It prints out a hashmark histogram (frequency chart).  You have to enter the data in descending order. I suppose it would be nice to have it accept data in any order, but whateva'.
            </xhtml:p>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='histogram.png' target='_blank'><xhtml:img src='thumbnails/histogram.png'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    Here's a screenshot of histogram in action.
                </xhtml:div>
            </xhtml:div>
            <xhtml:p>
            Here is the source code.  Note that it must be linked with the math library (-lm in Unix).
            </xhtml:p>
            <xhtml:p>
            <xhtml:code><xhtml:a href='histogram.c'>histogram.c</xhtml:a></xhtml:code>
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>SDH</name>
        <short-description>subversion diff highlighting</short-description>
        <years>2005</years>
        <description>
            <xhtml:p>
            SDH is a tiny C program which highlights the output of the `svn diff` command. I use a bash shell alias set up to pipe it into `less`:
            </xhtml:p>
            <xhtml:p>
            <xhtml:code style='margin:20px'>alias svndiff='svn diff --no-diff-deleted | sdh | less -r'</xhtml:code>
            </xhtml:p>
            <xhtml:div class='wide-image-box'>
                <xhtml:center>
                    <xhtml:a href='sdh.png' target='_blank'><xhtml:img src='thumbnails/sdh.png'/></xhtml:a>
                </xhtml:center>
                <xhtml:div class='caption'>
                    Here's a screenshot of histogram in action.
                </xhtml:div>
            </xhtml:div>
            <xhtml:p>
            There's not much else to say.  Here's the source code:
            </xhtml:p>
            <xhtml:p>
            <xhtml:code><xhtml:a href='sdh.c'>sdh.c</xhtml:a></xhtml:code>
            </xhtml:p>
        </description>
      </subcategory>
      <subcategory>
        <name>Textbot</name>
        <short-description>timed text input replay program</short-description>
        <years>2005</years>
        <description>
            <xhtml:p>
            Textbot was a little utility I wrote to ease the tedium of manually testing console applications which require time-based input (i.e. where commands can not be buffered and serialized).  While not especially clever or robust, it got the job done.
            </xhtml:p>
            <xhtml:p>
            It works like this: you run your application "behind" textbot as such:
            </xhtml:p>
            <xhtml:p>
            <xhtml:code style='margin:20px'>./textbot stupid_app stupid arguments</xhtml:code>
            </xhtml:p>
            <xhtml:p>
            Textbot will eat directives (any line that starts with @).  The @help directive prints:
            </xhtml:p>
            <xhtml:pre style='margin:20px'>
*********************************************************
*** help
*********************************************************
*** @record &lt;name&gt;                   record a named macro
*** @play &lt;name&gt;                  play back a named macro
*** @loop &lt;number&gt;       start a loop of given iterations
*** @stop               end the most recent loop or macro
*** @macrolist              print list of recorded macros
*** @help                                    this message
*********************************************************
</xhtml:pre>
            <xhtml:p>
            Macros can be recorded and played back.  Looping is possible as well.  I thought I created a way to dump the recorded macros to a file for later reloading, but apparently not (or maybe I lost that particular version somewhere).  I'll probably add that (back) at some point.
            </xhtml:p>
            <xhtml:p>
            Source code (released under the GNU GPL version 2):
            </xhtml:p>
            <xhtml:p>
            <xhtml:code><xhtml:a href='textbot-20100607.zip'>textbot-20100607.zip</xhtml:a></xhtml:code>
            </xhtml:p>
            <xhtml:p>
            Textbot uses <xhtml:a href='http://flex.sourceforge.net/'>GNU Flex</xhtml:a> to generate the scanner code (I'm using version 2.5.35), though you shouldn't necessarily need flex to compile, since the generated scanner code files are included.
            </xhtml:p>
        </description>
      </subcategory>
    </subcategories>
  </category>
</categories>

</root>
