thoroughly rewritten; see README for changes