Older blog entries for johnw (starting at number 46)

A day for nostalgia

After tracking it down on a public domain mirror, and installing an emulator on my MacBook Pro, I was able to download and run the first full computer program I ever wrote: “Sector Inspector” for the Apple //e.

I wrote this program in 1989, and took eleven months to write it (seven to code, four to debug). At the time, it was one of the more complete disk editing utilities I’d seen.

It was released as Shareware (for $20), and I made a total of $60 over the course of eight years. This is the experience that turned me to freeware, actually; because I realized that coding for possible, yet unrealized profit was an unlikely aim. It’s better to know that little will come of it ahead of time, which makes it all about the coding.

Sector Inspector was written using the Merlin Prodos Assembler. It took thirteen minutes to assemble on my Apple //e, four using a friend’s hardware accelerator card. In those days I owned a 1Mb expansion card, and would do all of my development there (for the sake of speed), frequently saving to 5.25” floppies.

When finished Sector Inspector printed to 255 pages of assembly code, which was registered with the US copyright office. I tried selling it to three different software companies at the time, but only responded positively — the authors of Merlin, who said they couldn’t publish another title, but offered me a job instead. I didn’t take the job (I don’t know why), and instead released the program as Shareware.

I remember having dreams that IS would make around $10k, and with that money I would buy a color Macintosh IIfx, all the rage at the time. Those dreams never materialized, of course, and shortly afterward the //e was cancelled, Prodos 8 was cancelled, and I started working on UNIX machines. The next year I worked for Network Solutions and used that money to buy a NeXT workstation, and said goodbye to the Apple world for a very long time (until just a few months ago, when I bought a PowerBook G4).

Here is a screenshot of the splash screen on startup:

screenshot of the startup screen

And a screenshot of the main window:

screenshot of the main window

You can download an Apple //e disk image of Sector Inspector, and play around with it, or read the FEATURES document I wrote as a young 17 year old programmer.

Syndicated 2009-01-20 03:36:57 (Updated 2009-01-20 07:39:30) from Lost in Technopolis

Linux DHCP and Windows DNS

I feel a need to blog about this today because it took several days to figure out, but the solution was trivial.

The scenario: my company has a Windows 2003 Domain Controller running DHCP, DNS and Active Directory services. We use an Untangle box as our gateway to the Internet. All of this works just great for Windows machines on the network, where everyone can use names like “host” to refer to each other’s machines.

However, the Linux boxes until now have been second-class citizens. They are able to get IP address via DHCP, but Windows knows nothing about their hostnames. Nearly all of our Linux boxen run CentOS 5, which is to say, Redhat 5 (RHEL).

The solution, it turns out, is two-fold:

  1. On the Windows Domain Controller, go to the admin page for “Active Directory Users and Computers”. Under “Users” for your domain, create a new user named something like “dhcp4dns”. Pick a random password.

  2. On the same machine, go to the admin tool for DHCP and right-click on your domain and select Properties. Click on the DNS tab and check everything, while also selecting “Always dynamically update DNS A and PTR records”. Then click on the Advanced tab and its Credentials… button. Here enter the details for the user you created in step 1.

  3. This step is for CentOS: For every Linux box, edit the file /etc/sysconfig/networking/devices/ifcfg-eth0 (or whichever interface faces your local network).

Add the following line to that file, replacing hostname with your unqualified hostname:

  DHCP_HOSTNAME=_hostname_

Now just reset networking on the Linux box:

  # ifdown eth0 ; ifup eth0

Voila, your Windows server should now see the Linux box’s name just like everyone else on the network.

Syndicated 2009-01-16 19:42:45 (Updated 2009-01-18 01:27:13) from Lost in Technopolis

Ledger 2.6.1 released

Ledger 2.6.1 is released today. This is a bug fix release only, which fixes some blocking issues relating to the -p and -e options. It is a recommended upgrade for all Ledger users. It may be downloaded here

Work now turns fully to the upcoming 3.0 release, which represents a substantial code cleanup and rationalization of the user interface and several internal facilities. It will also focus on Python integration and better value expression handling.

Syndicated 2008-09-17 11:31:26 (Updated 2009-01-17 20:58:35) from Lost in Technopolis

Ledger 2.6.1 released

Ledger 2.6.1 is released today. This is a bug fix release only, which fixes some blocking issues relating to the -p and -e options. It is a recommended upgrade for all Ledger users. It may be downloaded here

Work now turns fully to the upcoming 3.0 release, which represents a substantial code cleanup and rationalization of the user interface and several internal facilities. It will also focus on Python integration and better value expression handling.

Syndicated 2008-09-17 11:31:22 from johnw@newartisans.com

Too much good stuff

A rundown of some of the cool things I’ve been playing with lately, which have distracted me from blogging...

Syndicated 2008-09-05 23:46:10 from johnw@newartisans.com

Omitting Git-ignored files in Emacs dired

Adding the following snippet to your .emacs file will cause Emacs’ dired mode to omit all files ignored by Git. This only works if you have dired-omit-mode on, which is ordinarily bound to Meta-o.

(add-hook ‘dired-load-hook #’(lambda nil (load “dired-x” t)))

(defvar dired-omit-regexp-orig (symbol-function ‘dired-omit-regexp))

(defun dired-omit-regexp ()
  (let ((file (expand-file-name “.git”))
        parent-dir)
    (while (and (not (file-exists-p file))
                (progn
                  (setq parent-dir
                        (file-name-directory
                         (directory-file-name
                          (file-name-directory file))))
                  ;; Give up if we are already at the root dir.
                  (not (string= (file-name-directory file)
                                parent-dir))))
      ;; Move up to the parent dir and try again.
      (setq file (expand-file-name “.git” parent-dir)))
    ;; If we found a change log in a parent, use that.
    (if (file-exists-p file)
        (let ((regexp (funcall dired-omit-regexp-orig)))
          (assert (stringp regexp))
          (concat
           regexp
           (if (> (length regexp) 0)
               “\\|” “”)
           “\\(“
           (mapconcat
            #’(lambda (str)
                (concat “^”
                        (regexp-quote
                         (substring str 13
                                    (if (= ?/ (aref str (1- (length str))))
                                        (1- (length str))
                                      nil)))
                        “$”))
            (split-string (shell-command-to-string
                           “git clean -d -x -n”)
                          “\n” t)
            “\\|”)
           “\\)”))
      (funcall dired-omit-regexp-orig))))

A note to fellow Emacs coders: I tried writing this as a piece of defadvice, rather than hijacking the definition of dired-omit-regexp, but for some reason it never called this function.

Syndicated 2008-08-12 07:22:26 from johnw@newartisans.com

17 Jul 2008 (updated 19 Jan 2009 at 05:06 UTC) »

A new Ledger mailing list

The Ledger project now has a new mailing list, hosted at Google Groups. This was requested by several users who were not happy with the current web forums being used. Note that you do not have to join the group just to post a question. I’ll be keeping the web forums up for another year or so, but will start discouraging their use.

Also, you can find a few of us on IRC at irc.freenode.net, on the channel #ledger. My own nick is “johnw”. Come say hello!

Syndicated 2008-07-17 00:02:40 (Updated 2009-01-17 20:59:36) from johnw@newartisans.com

Using Git as a versioned data store in Python

Git has sometimes been described as a versioning file-system which happens to support the underlying notions of version control. And while most people do simply use Git as a version control system, it remains true that it can be used for other tasks as well.

For example, if you ever need to store mutating data in a series of snapshots, Git may be just what you need. It’s fast, efficient, and offers a large array of command-line tools for examining and mutating the resulting data store.

To support this kind of usage – for the upcoming purpose of maintaining issue tracking data in a Git repository – I’ve created a Python class that wraps Git as a basic shelve object. Here is how you normally use the standard shelve module:

  import shelve

data = shelve.open('data.db')

# data.db may or may not have existed on disk before now. If not,
# We're Manipulating an Empty Dictionary. If so, we can examine or
# modify the previous run's state data. In both cases, the database
# is manipulated like a standard Python dictionary.

data[key] = "Hello, world!"
data.sync() # Write out changes to the dictionary

del data[key]
data.close() # Close and clean up, sync'ing only if necessary

This provides the simplest kind of database, without any query language or notion of whether previous state did or did not exist. Both of those are services you’d have to layer on top of the shelve object if you wanted them.

Now consider gitshelve. Whereas the Python shelve module stores your data by pickling all of the dictionary values, I pass whatever data you place in the dictionary straight on to Git’s standard input. In the default mode, this means you work strictly with string data:

  import gitshelve

data = gitshelve.open(repository = '/tmp/data.git')

data[key] = "Hello, world!"
Data.Sync() # Repository is created if it doesn't exist

del data[key]
data.close()

The interface is identical, but with the Git version you can now examine the resulting repository’s yourself, using regular Git commands:

  $ GIT_DIR=/tmp/data.git git log

By default, the commits have no associated comment text, but the sync method doesn’t accept parameters. If you wish to add transaction notes, use the commit method instead:

  data.commit("This is a comment")

You can store data this way either in a separate repository, or in named branches within any repository. If the repository argument is not given, the named branch within the current Git repository is used. An exception will be raised, however, if you do this and there is no Git repository related to the current directory.

  # I'm expecting to use the 'data' branch of the current repository, but
# I ran the script in a directory unknown to Git!
data = gitshelve.open(branch = 'data')

# It appears to work, because no Git commands are run until the last
# possible moment
data['foo/bar/hello.txt'] = "Hello!"

# This raises an exception, because there is no current repository. To fix
# it, either run "git init", or use a specific 'repository' argument above.
data.commit("I just said hello")

The really nice thing about using Git this way is that you get all of its best features for free.

Added non-text values

If you have a need to store non-textual values, you’ll have to let gitshelve know how to deal with them. I don’t do any such handling by default, because of the big chance of doing the wrong thing, and having you not find out about it until it’s much too late. Just pickling data like shelve does isn’t very smart, for example, because it will wreak havoc on Git’s merge algorithms should you ever need to incorporate new data from another source.

So, let’s see how to add a custom data translator. First, you need to subclass a new type of gitbook, which is the wrapper used to interface with the blobs in the Git repository. There are only two methods you need to override:

  class my_gitbook(gitshelve.gitbook):
def serialize_data(self, data):
return object_to_string(data)

def deserialize_data(self, data):
return object_from_string(data)

Now you must define object_to_string and object_from_string, which should examine the types of the objects passed and turn them into merge-friendly string as appropriate. Certain forms of XML work well for this job, as do ini-style configuration files in some cases. It’s up to you and what works best for your usage.

Once you have this new class type, you must pass it to the gitshelve.open function:

  data = gitshelve.open(repository = '/tmp/foo', book_type = my_gitbook)

Making things even faster

Every time you open a gitshelve, it must walk through the assoicated branch and determine its contents in order to build the key/value relationships in the dictionary. If you find that this ever gets slow, what you can do is just pickle the gitshelve! The only caveat is that you must take care to delete it if the HEAD you created it from is different from the current HEAD. Here’s an example:

  import gitshelve
import cPickle
import os

data = None
if os.path.isfile('data.cache'):
fd = open('data.cache', 'rb')
data = cPickle.load(fd)

# I'm using an arbitrary file name here, __HEAD__
if data['__HEAD__'] != data.current_head():
data = None # Out of date, we can't use it

if not data:
data = gitshelve.open(branch = 'data')
data['__HEAD__'] = data.current_head()

# ... for data sets with enormous quantities of tiny files, this
# could really speed things up ...

Where can you get it?

The gitshelve module is being maintained as part of the git-issue project, which is yet another attempt to bring distributed bug tracking to Git. Actually, I tend to support multiple repositories as data backends, but right now Git is my initial focus. You can clone the project and test it out as such:

  git clone git://github.com/jwiegley/git-issues.git
cd git-issues
python t_gitshelve.py

If see “OK” at the end of the unit tests, you’re good to go! There isn’t much documentation on gitshelve.py itself right now, beyond this blog entry, but then again the shelve-like interface is simple enough that you really shouldn’t need much more.

Syndicated 2008-05-15 04:00:59 from johnw@newartisans.com

Emacs Chess now hosted at GitHub

Emacs Chess is a fully featured chess client written entirely in Emacs Lisp. You can use it to play against other people on freechess.org, or against popular chess engines like gnuchess and crafty. It supports graphical rendering of chess boards within Emacs (in 2D), ASCII displays, and even electronic chess boards, or producing output appropriate braille for readers. Adding a new back-end is trivial. It also comes with a library for inspecting and reasoning about chess positions.

This project is looking for someone who loves Emacs, Lisp and the game of chess, to fork it and take over as maintainer. The FSF has agreed to include Emacs Chess as part of the Emacs distribution, but I’ve held off because of a few remaining issues I want to see resolved before it goes mainstream. It does work quite well, however, and I have friends who use it as their sole client for playing chess online.

Emacs Chess is now being hosted at GitHub, which should make it easier for others to contribute:

  http://github.com/jwiegley/emacs-chess

If you’d like to just clone it and try it out, run the following and then see the README:

  git clone git://github.com/jwiegley/emacs-chess.git
cd emacs-chess
git submodule init
git submodule update # grab the 2D pieces and sound sets
make

After it compiles, add the emacs-chess directory to your load-path, load chess.el, and then type M-x chess!

If anyone is interested in taking over as the maintainer, or would like to contribute those last few weeks of work necessary to getting this project delivered with GNU Emacs, please contact me.

Syndicated 2008-05-08 20:49:57 from johnw@newartisans.com

Ready Lisp version 20080428 now available

There is a new version of Ready Lisp for Mac OS X available. This version is based on SBCL 1.0.16, and requires OS X Leopard 10.5. The most notable change from the previous version is that 64-bit mode and experimental threading are no longer supported, since both have been known to have issues on OS X, while the purpose of Ready Lisp is to smoothly introduce Common Lisp to new users.

What is Ready Lisp? It’s a binding together of several popular Lisp packages for OS X, including: Aquamacs, SBCL and SLIME. Once downloaded, you’ll have a single application bundle which you can double-click – and find yourself in a fully configured Common Lisp REPL. It’s ideal for OS X users who want to try out Lisp with a minimum of hassle. The download is approximately 76 megabytes.

There is a GnuPG signature for this file in the same directory; append .asc to the above filename to download it. To install my public key onto your keyring, use this command:

  $ gpg --keyserver pgp.mit.edu --recv 0x824715A0

Once installed, you can verify the download using the following command:

  $ gpg --verify ReadyLisp.dmg.asc

For more information, see the Ready Lisp project page.

Syndicated 2008-05-05 06:21:58 from johnw@newartisans.com

37 older entries...

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!