PrintStar's Blog
Ramblings of a Fortran Nut
February 6, 2013 by Jeff

Building Python Extensions with Simply Fortran

Aside from maintaining Simply Fortran, I spend a good deal of my time working in Python.  As one might guess, I also spend most of my time working on various versions of Windows these days.  Many (many, many…) people online complain about the difficulties in working with Python on the Windows platform.  Generally speaking, though, I encounter few issues on the Windows platform with the exception of C extensions.

Python modules that incorporate C extensions (or Fortran or C++) require a compiler to be present obviously.   On GNU/Linux systems, there usually isn’t an issue as most distributions either already have or make it trivially simple to install the GNU Compiler Collection.  On Windows, however, the issue  is a bit more complicated.

Python’s distutils module does provide support for a  handful of compilers: Microsoft Visual C++ (the default), Cygwin’s GCC, Borland C/C++ (really?), and MinGW32′s GCC.  Using Microsoft’s compiler introduces some complexity, especially what version to install.  Cygwin usually isn’t desirable as it introduces dependencies on Cygwin’s DLL.  I personally don’t know anyone who uses Borland’s products any longer.  That leaves MinGW as a sensible compiler.

At this point, I’ll assume that the reader has installed Simply Fortran.  The package includes a fully configured and complete version of the MinGW-w64 GNU C, C++, and Fortran compilers.  Additionally, the compilers will be added to the path, so typing gcc –version or gfortran –version at the Windows command prompt should present some compiler version information.  Just having the compilers on the path overcomes one of the larger hurdles in setting up an environment for building Python extensions.

Next, let’s assume that the reader will be working with 32-bit Python on Windows.  64-bit Python on Windows is problematic in that the only supported compiler is Visual C++, adding some additional trouble.  There is currently an enhancement ticket to support MinGW-w64 in the core Python bug tracker, but, at this time, it simply isn’t usable without some annoying steps.  For most purposes, 32-bit Python should be sufficient (at least at the time of writing this post).

The first step is to direct Python’s distutils to always use Simply Fortran’s compiler.  By default, building an extension via python setup.py build is going to result in a cryptic error about a batch file that implies something about Visual C++.  To permanently direct Python to use Simply Fortran’s compiler, you’ll need to either create or edit a file at <Python Installation>\Lib\distutils\setup.cfg, adding the following:

[build]
compiler=mingw32

This little addition directs Python to try to use MinGW32 compilers by default.  However, some users may have noticed a discrepancy.  In the setup.cfg file, we have instructed Python to use MinGW32′s GNU C compiler, but Simply Fortran provides a version of the MinGW-w64 GNU C compiler.  The default output of Simply Fortran’s compiler will be 64-bit code, but we need to build 32-bit code in this described configuration.

The next step is to modify some of distutils code to account for our 64-bit compiler.  The configuration of the MinGW32 compiler can be found in the file <Python Installation>\Lib\distutils\cygwinccompiler.py.  Personally, I would suggest opening it with Simply Fortran as it understands Python code quite well.  Next, search for “-mno-cygwin” in this file.  This text is a somewhat dated compiler flag that instructs GNU compilers to avoid dependencies on Cygwin.  MinGW-w64 compilers (and modern MinGW32 compilers, I believe) don’t understand this compiler option.  In our case, though, we need to instruct the Simply Fortran compilers to build 32-bit code every time.  This search gives us the opportunity to add the flag “-m32” to the compiler flags.  My suggestion is to replace every occurrence of ”-mno-cygwin” with ”-m32” in cygwinccompiler.py.  In Python 3.3, for example, there should be exactly five occurences, all in lines 296 through 300, in cygwinccompiler.py.

Before closing this file, one more change is necessary.  The default configuration also instructs the compiler to link with the Microsoft Visual C runtime that matches with the version used to build the Python interpreter.  Attempting to do this with Simply Fortran’s compiler will almost certainly fail.  Instead, search for the following in cygwinccompiler.py:

self.dll_libraries = get_msvcr()

Change the above line to be:

self.dll_libraries = [] #get_msvcr()

This change just removes the attempted linking with the Visual C++ runtime.  Save cygwinccompiler.py and close the file.

Python should now be configured to build extensions.  As a test, I suggest downloading the Python source archive and attempting to build the example in  PC\example_nt.  Type python setup.py build and watch as Simply Fortran’s compiler builds the C extension module.  For a self-contained non-trivial example, try the crc16 module.

Readers might now be wondering about building NumPy or SciPy extensions (or SciPy itself).  NumPy, however, has its own distutils configuration that requires modification.  If you attempt to build a NumPy extension, things might seem to go well for a while, but it won’t exactly work.  Setting up NumPy is a whole other article.

  •   •   •   •   •
February 4, 2013 by Jeff

Updates to Open Watcom Make

As part of Simply Fortran, I maintain a minor fork of Open Watcom‘s Make utility, which anyone can see on my GitHub account.  Oddly, wmake, the abbreviated name for the utility, does occasionally allow interaction with the user on certain errors.  I’ve seen the occasional error asking if a file should be deleted after compilation fails.  The strangest part of the error is that the behavior is erratic at best.

I decided to change wmake’s default behavior to never interact with the user.  If interaction should ever be allowed, a new switch, -g, can be used.  After implementing it, however, I noticed that a switch to force deleting targets whenever an error occurred.  The -e switch instructs wmake to delete files on errors without a prompt.  I find it odd that the original Open Watcom developer decided to make interaction the default.

The source tree has two points where interaction is occurring.  I’d say there is no harm in defaulting to never talking with the user.  The -e flag, however, will be added to Simply Fortran’s default call to wmake.

Release

I was under the impression that “Release” archives could be uploaded to GitHub.  Apparently the feature was deprecated at the end of last year, though.  For that reason, I’ll post the released binaries here if anyone at all is interested:

If anyone finds any bugs, leave an issue on my GitHub account.  These binaries are provided merely for convenience.

  •   •   •   •   •
January 29, 2013 by Jeff

Python 3.3 on an Atari: Part 3

I ended my last post noting that I had seemingly successfully overcome the disaster that was the Atari’s wide-character support.  There were a few additional hiccups along the way of finalizing the wide-character support.  After having replaced almost every wide-character source file in the MiNTLib, I was still having issues with paths, for example.  It turned out that I had failed to replace the function mbstowcs() since it lived in a file I hadn’t expected.  Finding that gem led to implementing most of musl’s multibyte functionality as well.  With mbstowcs() implemented properly, my Python interpreter was finally reading in actual Python code from its standard library.

The MiNTLib was also missing two minor definitions.  The first was sched_yield(), which appeared defined in a header file, but kept popping up as undefined during the linking phase.   Searching the library didn’t reveal any actual function, so I dropped in a simple stand-in that basically asked the program to sleep for a very brief moment.  The second was nl_langinfo(), a simple function for retrieving a specific aspect of the locale.  Since the Atari’s support of locale’s was pretty minimal in most respects, a basic implementation would suffice.  After these last two bugs, I was able to compile.

I finally found myself faced with a nasty little error.  The interpreter would complain about an ImportError of some sort upon startup.  The most annoying aspect of this particular ImportError was that it was reported by the interpreter as “Could not import runpy module.”  Doesn’t seem particularly useful, right?  Having never heard of such a module, I looked in the standard library for the offending code.  There was a runpy module, but there was no obvious reason why it couldn’t be imported.  I next tried a search to hunt down where the error was issued from.  It turns out that the error originated in the interpreter startup code in Modules/main.c.  I was annoyed to find that, if the import of this module failed for whatever reason, it would spit out this short, vague message and exit.  An error was available, and I still don’t know why the developer who authored this code didn’t spit out the resulting exception.  To fix the issue, I decided to dump the Python error to stdin.

The source of the error appeared to be a failure to import the imp module, which provides much of the necessary infrastructure for, well, importing modules.  The source of the failure was a line where some functions from the _imp module were imported.  The _imp module, in turn, is a C module compiled into Python itself.  I had actually encountered it earlier when trying to figure out the wide-character mess, mistakenly assuming the C _imp module was actually the imp module, which was failing to load thanks to the MiNTLib (in fact, the _imp module internally thinks it is named the imp module…).

The error occurred because the imp module was attempting to load the function load_dynamic from the _imp module.  This function is linked to a pure-C function, imp_load_dynamic(), that is only compiled on platforms where shared libraries are supported.  Because Atari computers effectively have no true shared objects, I disabled all shared libraries during the build, meaning imp_load_dynamic() was never defined.  Becuase it wasn’t defined, the imp module was throwing an error during import.

This bug was reported on the core Python bug tracker after revealing itself.  The simple fix is to either not import load_dynamic at all, which works dandy for the Atari, or to set load_dynamic to None if not present, which is the suggested fix.  By fixing this minor issue, the interpreter was able to spring to life, presenting me finally with a fully function Python 3.3 prompt:

Python 3.3 on the Atari!

  •   •   •   •   •
January 8, 2013 by Jeff

Python 3.3 on an Atari: Part 2

In my previous post about bringing Python 3.3 to the Atari, I mentioned that the end result was yet another completely nonfunctional Python 3.3 executable. In an effort to find out what had gone terribly wrong, I fired up GDB on the ARAnyM virtual machine to sort out what had occurred.

I started with letting the interpretter run to see if an error that I could understand had occurred.  The problem with starting this way is that the Python interpretter is anything but simple.  I don’t mean this description in a bad way, just that blindly walking into what is occurring is somewhat daunting.  In the end, I couldn’t figure a thing out.

The interpretter was crashing with two major symptoms.   First, it complained about the environment and ‘<prefix>’ directories not being defined properly.  This crash seemed particularly odd since it shouldn’t be looking for environment settings; the crash was occurring as  a step in the Python build process after the executable was built but before the system was installed.  Second, it threw an import error complaining it couldn’t import the imp module.  Not loading the imp module concerned me greatly as this was necessary to import anything else.

I started with trying to figure out the failure to import imp. Looking through the builtin C modules, I noticed the import module was trying to call itself  imp. However, a bit further down the road, it was actually assigned the name _imp. In the Lib directory, however, there was an imp.py, which was actually what was necessary.  I spent some time making sure it actually wanted to load the pure-Python file via a combination of GDB and some printf statements.

If this basic module was failing to be pulled in, I though that perhaps something was wrong with the bootstrap process.  At startup, most of the Python fun kicks off with importlib._bootstrap.  I noticed that this Python file existed in the Lib directory, and I decided to throw a few clever print() statements into the code to see where things were going wrong.  Changing this file, however, changed nothing.

Back in the Python C code, I added a few more printf statements to try and track down the issue.  When I rebuilt the executable, though, I was met with an entirely new build error.  An executable named freeze_importlib had caused a nasty error.  This error had obviously never occurred before because I always arrived at a complete, but not working, executable.  Examining the command calling this executable, it was clearly reading in importlib._bootstrap and writing out a header file.

Firing up GDB, I ran freeze_importlib with the same arguments as the Makefile provided.  After a bit of tracing, I found that the failure came when it attempted to compile the Python to bytecode.  I was at a loss.

There were a number of points, though, that I had to keep in mind:

  1. The build didn’t work on the Atari platform – it worked just fine almost everywhere else, though
  2. Python 2.7 did work on the Atari platform – there was some massaging, but nothing extreme
  3. Python 3.x uses Unicode for almost everything – or that was my understanding at least, while Python 2.7 did not

Looking at these three points, I suspected the issue stemmed from mintlib’s embarrassingly incomplete support for wide character functions.  Recall that I had grafted on three functions, wcschr, wcsrchr, and wcstok, from FreeBSD just to get Python to compile.  I had to do a similar procedure with Python 2.7, but I never tested any Unicode functions under that interpretter.  I decided to go out looking for some proper wide character support.

Obviously I wasn’t going to bother looking at GNU libc’s implementations.  I was concerned that those might be a bit confusing.  Using Wikipedia,  I searched for some C standard library implementations that weren’t GNU libc.  I ended up downloading a handful of them and examining their support for wide characters.  The musl implementation, though, seemed the smallest, simplest, and most straightforward.  I especially liked that it was, “Designed from the ground up for static linking,” since there’d be no dynamic linking under FreeMiNT on the Atari.

I didn’t want to replace all of mintlib with musl, just every bit of wide character support.  In the mintlib build tree, I deleted every mintlib mention of wide character functionality, and I created some dynamic links back to the musl library’s directory tree.  After a few speedbumps and editing a list of C files in mintlib, I successfully built a new mintlib with every wide character function replaced.

Back in the Python directory, I decided to reattempt building the Python executable against my new mintlib.  I cleaned and restarted the build process (slow even with ARAnyM on a relatively quick Athlon-based system) and waited expectantly.  I had not un-modified the print() additions in importlib._bootstrap, however, meaning that the freeze_importlib executable would be run again.  When the Makefile reached the freeze step, I smiled as it progressed happily past building the necessary header file, continuing on with the build process.

My smile didn’t last long, though, as the Python executable was launched by the make process.  Once again, an ImportError popped up saying the interpretter couldn’t import imp.  Something was still amiss…

  •   •   •   •   •
January 8, 2013 by Jeff

WordPress Double-Apostrophe

I’ve been puzzled for a bit as to why every apostrophe in my blog is doubled up. A symptom that I noticed writing my last post was that these apostrophes would continue to multiply every time I saved a draft. Looking through the WordPress code, I suspected that a filter was at play or my switch to an SQLite backend may have caused the issue.

I did finally find a post related to the exact behavior I was seeing:

http://www.markchicobaby.com/2009/03/02/how-to-fix-double-apostrophe-in-wordpress/

Apparently, a  PHP setting was to blame.  Easy to change, right?  I made the change (even though it appeared to be globally disabled already) and quickly tested it with this very post.   I was disappointed to find that it  didn’t fix the problem.

The big difference between my WordPress install and others is the fact that I’m using an SQLite backend based on a somewhat outdated WordPress plugin, PDO for WordPress.  My installation is further complicated by the fact that it was hacked to run under WordPress 3.x, which it certainly wasn’t meant to do.

Again, the issue had to be related to using SQLite somehow.  I’m not implying that it is SQLite’s fault (SQLite is a spectacular database), but, rather, the plugin that interfaces with it.  Turns out that I was able to fix the problem by disabling escaping the query.  Is this practice safe?  Almost certainly not.   My guess, however, is that the query was already escaped properly elsewhere.  I think some usage will be necessary to eventually determine if my fix is correct.

  •   •   •   •   •
January 7, 2013 by Jeff

Python 3.3 on an Atari: Part 1

Back in 2011, I successfully attempted to get Python 2.7 running on the Atari platform, culminating in a PyOhio presentation demonstrating the port. I pointed out during that presentation that my ultimate goal was to bootstrap Python 3.x on the Atari, but my successful compilation of the interpreter yielded an executable that didn”t seem to do anything. After having a subsequent talk rejected from PyCon (twice, actually, and I”m starting to think nobody cares about Python on the Atari…), I let the project simply fade.

Over the last few weeks, however, I decided to give it a shot once again for fun. I recompiled the latest ARAnyM emulator for two of my desktops and set out again on this adventure in retrocomputing.

About the Atari

My goal was to compile Python 3.3 for the FreeMiNT operating system running on the Atari ST/TT/Falcon line of computers. The last Atari-built computer was probably manufactured in the early to mid nineties, making the platform somewhat dated. The machines ran on the Motorola 68k series of CPUs. The FreeMiNT operating system, originally known as MiNT, then MultiTOS, then MiNT again, and finally FreeMiNT, is an odd concept to people unfamiliar with the Atari platform. Basically, the operating system provides a BSD kernel with full preemptive multitasking for the Atari machines. The odd part is that FreeMiNT doesn”t actually replace the entirety of the Atari”s operating system in ROM, TOS; rather, it simply replaces the parts that need replacing to allow multitasking. It”d be as if the Linux kernel could boot from DOS, but allow DOS sound drivers to manage sound cards or something equally as odd.

FreeMiNT is normally beefed up with a significant number of add-ons. Basically, my current install on the ARAnyM virtual machine boots into a Atari TOS-compatible GUI comprised of a replacement Virtual Device Interface (fVDI) and Application Environment Services (XaAES). Additionally, using TosWin2, I can open a bash prompt on the machine, where it behaves similar to most UNIX-y free operating systems, the big difference being that it continues to maintain full compatibility with the bare Atari TOS (more or less, but let”s not stroll down that path).

Since I can get to a bash prompt, one might think that the only step involved in building Python on the Atari is a pair of commands: configure and make. There is, of course, far more involved.

Compiling on the Atari

Under FreeMiNT, the de facto compiler continues to be GCC 2.95.3. There are more modern versions available for the platform, but only 2.95.3 is packaged for the SpareMiNT distribution, an RPM-based FreeMiNT installation and arguably the only one still maintained. Using 2.95.3 from SpareMiNT also has the added bonus of allowing prebuilt binary libraries to be used rather than having to manually build Python”s meager dependencies.

There are ports of the GCC 4 series to compile Atari software. However, most ports are cross compilers, requiring the software to be built on a PC. Anyone familiar with building CPython should know that cross compiling Python is basically never suggested. Additionally, the Atari line of computers are desktop systems, not embedded devices; having to cross compile software for them feels dirty and pointless.

To build Python, in this case, I decided on sticking with GCC 2.95.3 as planned. So now I can just type configure and make, right? You can, but you”ll immediately get some errors. Actually, using the stock Python distribution, you”ll get relatively far before encountering an error in a Python header file itself. Before we dig into what”s wrong with Python, though, we first need to discuss the problems surrounding mintlib.

Although FreeMiNT mostly relies on GCC as its compiler, it does not use the GNU Libc standard library. Rather, it uses a C runtime library called mintlib. This C runtime library is a mishmash of standard C functions as one would expect with some of the historically lesser used functions grafted on from various other implementations. Different portions are governed by different licenses, including old and new BSD and the GNU GPL. I”m not sure mintlib is actually conforming to some of the licenses, but it”s obscure enough that probably nobody will care.

During my work porting Python 2.7, I encountered some missing standard library calls related to wide characters. The Atari runtime library did not contain wcschr() and wcsrchr() functions. I threw together a little library containing these function from their FreeBSD implementations, allowing me to build Python 2.7 to completion. I also needed to do this when I attempted to build Python 3.2 during that same period, but, as I said, the resulting executable was completely nonfunctional.

I decided to do the same thing here to get Python 3.3 booting. Basically, I built a little library containing the two functions above and wcstok(), another missing function, to get the build to progress. Although I was able to get the build to complete (with some other changes I'll explain in a later post), I ended up with a completely nonfunctional executable once again. My first reaction was to give up, but I decided to continue my quest for Python 3.3 on an Atari machine.

  •   •   •   •   •
November 30, 2012 by Jeff

A Second Novel!

For the second time, I participated in National Novel Writing Month, and, moments ago, I won for the second time!  For those unfamiliar  with the contest, participants must write a 50,000 word novel over the month of November.  The goal is not to write the next great American novel, but simply to actually write down that many words, forcing creativity and denying procrastination.  To meet that goal, I needed to write, on average, 1,667 words per day.  Adding in the fact that those words should contain some semblance of a plot, the task is not a simple one.

Last year I wrote a fantasy novel.  So far one other person in this world has read it, and my wife thought it was “good.”  My guess is that it was rather bad.

This year”s book is called “Soccer!”  It follows an adult, coed, recreational, indoor soccer team through a season.  It is written in the first person, which makes things complicated.  Additionally, trying to keep track of nine teammates, which is actually small for a team, gets a bit confusing.  The addition  of non-team characters only works to muddle the dialog further.

After 52,866 words, I have written second complete novel.  I”m pretty sure this one is worse than my first.

  •   •   •   •   •
June 25, 2012 by Jeff

A Published Novel? Neat!

Last November I had a post bragging that I successfully completed National Novel Writing Month, NaNoWriMo, finishing a 50,000 word novel in one month. Actually, I think mine is 52,000 or thereabouts depending on how the counting is done. Well, with that win came an offer for five free copies of my book, published and bound, from CreateSpace. That offer, however, gave me through June, 2012 to take advantage of it.  So once June 15th rolled around, it was time to get cracking.

My book has a lot of problems. A lot. Most notably, it was riddled with spelling errors because I wrote the entire thing on a Tandy Model 102 laptop, which doesn”t have spell check. Additionally, there were other oddities:

  • Quotes attributed to the wrong character, making their speech exceptionally odd
  • Complete lack of explanation about some character attributes, such as one character doesn”t like horses, but it isn”t actually ever brought up until the very last line of the novel (now redacted)
  • Confusing sentence structures

Over the last week, I”ve been reviewing my book endlessly.  I actually converted the entire book into TeX format so that I could pretty-print it.  Thankfully, TeXMaker, a TeX editor, incorporates spell check.

After a few days of editing, it was time to get started with “finishing” for CreateSpace.  There were some minor formatting issues related to page size, but CreateSpace had some wonderful verification tools.  The nastiest part was trying to get a cover that looked awesome.  I decided to create my own, which turned out okay:

So the cover could be better, but whatever.  The process was finally complete.  With 6 days to spare, I was able to order my five free copies, and I can”t wait to see them!

If anyone is interested in reading this odd little book (better than I remembered upon review), you can get it at CreateSpace or Amazon:

If anyone does actually read it, send me an email at jeff at rainbow-100.com.  I”d love to hear any comments!

  •   •   •   •   •
March 14, 2012 by Jeff

A PyCon Retrospective

Another PyCon ended for me this week, and now I have the long wait until next March’s conference. Being my second time attending, I was more aware of how to take advantage of the conference. However, after trip number two, I’ve learned a few things more.

The talks themselves were too numerous and spectacular to outline individually. In fact, I haven’t really started into the pages of notes I took during the conference. I know I’ve written down some true gems, but I think my brain could use a (comparable) rest for the remainder of the week at the very least. Instead, I wanted to talk about more general PyCon tips. Probably the best lightening talk I saw summed up many of the tips:

First PyCon Tips (not me, BTW)

Some important points that I learned, however, were things I learned last year as well.

Use Twitter

Last year a handful of people pointed out that they used Twitter extensively during the conference. I didn’t have a Twitter account because I honestly couldn’t think of a reason why. Right up until PyCon 2012 I kept reminding myself that I should probably sign up, but I never did.

Big mistake.

Twitter seemed to be more prevalent than ever this year. In fact, most every business card I received had a Twitter handle. I felt like an unconnected ass the countless times people asked me what my Twitter was. I learned my lesson, and now I can be followed at @fortranjeff.

Listen to Talks

My first year at PyCon, I was surprised at how many laptops were out during the presentations. Being a follower, I brought mine along and opened it at every talk. That’s where I became a little baffled about what to do next. Looking around, some people were taking notes, but others were coding, browsing, or checking email.

I tried doing some coding during talks, and I immediately noticed that I was missing giant portions of the talk. This year, while I did carry my heavy 15 inch Dell everywhere, I made sure to only take notes during talks. I found that I actually walked away with significantly more information. I guess the moral of the story is that it pays to listen to whoever is talking at the front of the room.

Never Hesitate to Talk About Yourself

This tip probably sounds rather pompous at first, but it isn’t meant to be. I’m not necessarily the most outgoing person. However, when at a conference alone, you need to be as outgoing as possible to make it worthwhile.

My problem, though, was often hesitation to talk about what I did. Last year, when traveling for my NASA-contracting employer, I would try to play down what I did as it didn’t seem as impressive as all the other people at PyCon. I don’t think that’s the right move. This year I was quite forthcoming with the fact that I own a small business developing a Fortran development environment. While this occasionally raised eyebrows or resulted in a chuckle, everyone seemed genuinely interested in the reasons behind it. Furthermore, sticking my neck out and chatting about what I do know about web frameworks and scientific programming always seemed to result in fantastic conversations where I learned plenty.

Other people need to follow this rule too. Just about everyone I met had a fascinating use case for Python, at least in my eyes. Then I can walk away from those conversations with knowledge like, “I’m going to check out this whole MongoDB deal,” or “I have to check what the standard library’s subprocess module does again.” Neither are “necessary” for my work, but both may turn out to be valuable at some point in my career.

Stick Around in the Evenings

I had some great conversations into the evenings with other attendees. It doesn’t hurt that most of the evening activities I participated in involved alcohol as it does “grease the wheels” nicely for everyone.

Consider Sprinting

Every year when the closing remarks are ending, I feel regret for not staying for sprints. This year was no different. I plan on staying next year for at least a day to see what they’re about.

So those are my rather lame tips for PyCon. I’ll of course attend next year, and hopefully I learn some more tips for getting the most out of the conference before then. At least now I don’t have to meekly state, “I don’t have a Twitter account.”

  •   •   •   •   •
November 29, 2011 by Jeff

Certified Novelist!

Today, just a few minutes ago, I became a certified novelist. I successfully complete the 2011 National Novel Writing Month by writing, from scratch, an original 52,099 word novel. For the entire month of November, I’ve been toiling over my Tandy Model 102 laptop trying to write a contiguous 50K+ word story. This evening I was able to write a short Epilogue, completing the story. I had been using a combination of OpenOffice and a custom BASIC program on the Tandy laptop to count my progress during the month. Moments ago, I concatenated the twenty chapters and uploaded the new novel Bringing Balance to the NaNoWriMo site for certification. I was thrilled when the message, “Congratulations, novelist! You’ve won!” appeared in my web browser!

I think my wife deserves some serious thanks for letting me get away with skirting some responsibilities during November in a quest to complete this book. Everyone should give this contest a try at some point. The whole process is fun, stressful, exciting, and fulfilling.

  •   •   •   •   •