GNU bug report logs -
#76870
31.0.50; server-start with non-nil arg LEAVE-DEAD can write confusing warnings
Previous Next
To reply to this bug, email your comments to 76870 AT debbugs.gnu.org.
There is no need to reopen the bug first.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#76870
; Package
emacs
.
(Sat, 08 Mar 2025 15:46:04 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
Jens Schmidt <jschmidt4gnu <at> vodafonemail.de>
:
New bug report received and forwarded. Copy sent to
bug-gnu-emacs <at> gnu.org
.
(Sat, 08 Mar 2025 15:46:04 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
* Original Reproducer
Start an Emacs session A with emacs -Q, start an Emacs server in that
with M-x server-start RET.
Now start another Emacs session B with emacs -Q and evaluate the
following with C-j in its *scratch* buffer:
(require 'server)
server
(unload-feature 'server)
nil
The call to `unload-feature' results in warnings:
⛔ Warning (server): Unable to start the Emacs server.
There is an existing Emacs server, named "server"
To start the server in this Emacs process, stop the existing server or call M-x server-force-delete to forcibly disconnect it.
* Simplified Reproducer
Start an Emacs session A with emacs -Q, start an Emacs server in that
with M-x server-start RET.
Now start another Emacs session B with emacs -Q and evaluate the
following with C-j in its *scratch* buffer:
(require 'server)
server
(server-start t)
nil
You get the same warnings as shown in the original reproducer.
* Analysis
According to the doc string and the implementation of `server-start', a
call
(server-start t)
with non-nil argument LEAVE-DEAD should just stop a running server. And
this also works perfectly well when the server is running locally in the
same Emacs session where `(server-start t)' gets executed.
However, if there is an external Emacs server running in an Emacs
session A, then `(server-start t)' from another session B obviously
cannot just stop that server. However, the warning issued in session B
as quoted above mentions that the server cannot be *started*.
1. So I think in case of non-nil LEAVE-DEAD and a running external
server, a more appropriate warning would be:
⛔ Warning (server): Unable to stop an external Emacs server.
There is an existing Emacs server, named "server"
Stop it either in its Emacs session or call M-x server-force-delete to forcibly disconnect it.
2. However, one could also argue that, if there is no local server
running, a call to `(server-start t)' should be completely silent.
That is at least what `(server-start t)' does if there is no server
(neither local nor external) running at all.
3. Or at least it should be silent if called from a non-interactive
context as shown in the original reproducer.
4. Or at the very least it should be silent if called from
`server-unload-function'.
Not sure what the "ideal" fix would be here, but I would be happy to
provide patches for any of the scenarios above.
Thanks!
In GNU Emacs 31.0.50 (build 22, x86_64-pc-linux-gnu, GTK+ Version
3.24.38, cairo version 1.16.0) of 2025-03-05 built on sappc2
Repository revision: e978737f57ef8447bba5796dd945ac185fcadffa
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.12201009
System Description: Debian GNU/Linux 12 (bookworm)
Configured using:
'configure --with-native-compilation --with-mailutils'
Configured features:
ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ JPEG
LCMS2 LIBOTF LIBSELINUX LIBSYSTEMD LIBXML2 M17N_FLT MODULES NATIVE_COMP
NOTIFY INOTIFY PDUMPER PNG RSVG SECCOMP SOUND THREADS TIFF
TOOLKIT_SCROLL_BARS WEBP X11 XDBE XIM XINERAMA XINPUT2 XPM XRANDR GTK3
ZLIB
Important settings:
value of $LC_COLLATE: POSIX
value of $LC_TIME: POSIX
value of $LANG: en_US.UTF-8
value of $XMODIFIERS: @im=ibus
locale-coding-system: utf-8-unix
Major mode: Lisp Interaction
Minor modes in effect:
tooltip-mode: t
global-eldoc-mode: t
eldoc-mode: t
show-paren-mode: t
electric-indent-mode: t
mouse-wheel-mode: t
tool-bar-mode: t
menu-bar-mode: t
file-name-shadow-mode: t
global-font-lock-mode: t
font-lock-mode: t
blink-cursor-mode: t
minibuffer-regexp-mode: t
line-number-mode: t
indent-tabs-mode: t
transient-mark-mode: t
auto-composition-mode: t
auto-encryption-mode: t
auto-compression-mode: t
Load-path shadows:
None found.
Features:
(shadow sort mail-extr comp-run bytecomp byte-compile comp-common rx
emacsbug lisp-mnt message mailcap yank-media puny dired dired-loaddefs
rfc822 mml mml-sec password-cache epa derived epg rfc6068 epg-config
gnus-util text-property-search time-date subr-x mm-decode mm-bodies
mm-encode mail-parse rfc2231 mailabbrev gmm-utils mailheader cl-loaddefs
cl-lib sendmail rfc2047 rfc2045 ietf-drums mm-util mail-prsvr mail-utils
rmc iso-transl tooltip cconv eldoc paren electric uniquify ediff-hook
vc-hooks lisp-float-type elisp-mode mwheel term/x-win x-win
term/common-win x-dnd touch-screen tool-bar dnd fontset image regexp-opt
fringe tabulated-list replace newcomment text-mode lisp-mode prog-mode
register page tab-bar menu-bar rfn-eshadow isearch easymenu timer select
scroll-bar mouse jit-lock font-lock syntax font-core term/tty-colors
frame minibuffer nadvice seq simple cl-generic indonesian philippine
cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao
korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech
european ethiopic indian cyrillic chinese composite emoji-zwj charscript
charprop case-table epa-hook jka-cmpr-hook help abbrev obarray oclosure
cl-preloaded button loaddefs theme-loaddefs faces cus-face macroexp
files window text-properties overlay sha1 md5 base64 format env
code-pages mule custom widget keymap hashtable-print-readable backquote
threads dbusbind inotify lcms2 dynamic-setting system-font-setting
font-render-setting cairo gtk x-toolkit xinput2 x multi-tty move-toolbar
make-network-process tty-child-frames native-compile emacs)
Memory information:
((conses 16 58238 9283) (symbols 48 6194 0) (strings 32 15317 1578)
(string-bytes 1 469817) (vectors 16 9913)
(vector-slots 8 139320 7677) (floats 8 23 12) (intervals 56 238 0)
(buffers 984 10))
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#76870
; Package
emacs
.
(Sat, 08 Mar 2025 16:05:02 GMT)
Full text and
rfc822 format available.
Message #8 received at 76870 <at> debbugs.gnu.org (full text, mbox):
> Date: Sat, 08 Mar 2025 16:45:27 +0100
> From: Jens Schmidt via "Bug reports for GNU Emacs,
> the Swiss army knife of text editors" <bug-gnu-emacs <at> gnu.org>
>
> * Simplified Reproducer
>
> Start an Emacs session A with emacs -Q, start an Emacs server in that
> with M-x server-start RET.
>
> Now start another Emacs session B with emacs -Q and evaluate the
> following with C-j in its *scratch* buffer:
>
> (require 'server)
> server
>
> (server-start t)
> nil
>
> You get the same warnings as shown in the original reproducer.
What happens in this recipe is expected, and is not a bug.
> However, if there is an external Emacs server running in an Emacs
> session A, then `(server-start t)' from another session B obviously
> cannot just stop that server. However, the warning issued in session B
> as quoted above mentions that the server cannot be *started*.
Which is the truth: server-start attempted to stop the (non-existent)
local server process, which silently succeeded, and then attempted to
start a new server process, which fails with the above message.
> 1. So I think in case of non-nil LEAVE-DEAD and a running external
> server, a more appropriate warning would be:
>
> ⛔ Warning (server): Unable to stop an external Emacs server.
> There is an existing Emacs server, named "server"
> Stop it either in its Emacs session or call M-x server-force-delete to forcibly disconnect it.
This doesn't seem to be very different from the current message. I
don't think the "in its Emacs session" part is significantly more
clear than "stop the existing server".
> 2. However, one could also argue that, if there is no local server
> running, a call to `(server-start t)' should be completely silent.
> That is at least what `(server-start t)' does if there is no server
> (neither local nor external) running at all.
>
> 3. Or at least it should be silent if called from a non-interactive
> context as shown in the original reproducer.
>
> 4. Or at the very least it should be silent if called from
> `server-unload-function'.
The only bug here is 4. Unloading the server feature should not cause
this warning. All the rest is the intended behavior.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#76870
; Package
emacs
.
(Sat, 08 Mar 2025 17:29:02 GMT)
Full text and
rfc822 format available.
Message #11 received at 76870 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
On 2025-03-08 17:04, Eli Zaretskii wrote:
>> Date: Sat, 08 Mar 2025 16:45:27 +0100
>> From: Jens Schmidt via "Bug reports for GNU Emacs,
>> the Swiss army knife of text editors" <bug-gnu-emacs <at> gnu.org>
>>
>> 1. So I think in case of non-nil LEAVE-DEAD and a running external
>> server, a more appropriate warning would be:
>>
>> ⛔ Warning (server): Unable to stop an external Emacs server.
>> There is an existing Emacs server, named "server"
>> Stop it either in its Emacs session or call M-x server-force-delete to forcibly disconnect it.
>
> This doesn't seem to be very different from the current message.
Except that I use the word "stop" instead of "start" in its first
line...
Do we agree that the following are all equivalent in effect
M-: (server-start t) RET
C-u M-x server-start RET
C-- M-x server-mode RET
and all should *stop* the server without restarting it?
If yes, then I find it confusing to read that Emacs could not
*start* the server in the resulting warning.
>> 4. Or at the very least it should be silent if called from
>> `server-unload-function'.
>
> The only bug here is 4. Unloading the server feature should not cause
> this warning. All the rest is the intended behavior.
How about the attached patch? (Which I would extend if we find
an agreement for case 1. as well.)
[0001-Silently-stop-the-server-if-unloading-its-library.patch (text/x-patch, attachment)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#76870
; Package
emacs
.
(Sun, 09 Mar 2025 10:40:02 GMT)
Full text and
rfc822 format available.
Message #14 received at 76870 <at> debbugs.gnu.org (full text, mbox):
> Date: Sat, 8 Mar 2025 18:27:50 +0100
> Cc: 76870 <at> debbugs.gnu.org
> From: Jens Schmidt <jschmidt4gnu <at> vodafonemail.de>
>
> >> ⛔ Warning (server): Unable to stop an external Emacs server.
> >> There is an existing Emacs server, named "server"
> >> Stop it either in its Emacs session or call M-x server-force-delete to forcibly disconnect it.
> >
> > This doesn't seem to be very different from the current message.
>
> Except that I use the word "stop" instead of "start" in its first
> line...
But that is confusing. This message is for the case when the user
wants to start a server; the fact that the previous one should be
stopped is a side effect. So talking about "stopping" will confuse,
IMO.
> Do we agree that the following are all equivalent in effect
>
> M-: (server-start t) RET
>
> C-u M-x server-start RET
>
> C-- M-x server-mode RET
>
> and all should *stop* the server without restarting it?
Yes.
> If yes, then I find it confusing to read that Emacs could not
> *start* the server in the resulting warning.
So you want to have an alternative message about stopping only? That
could be a good idea, yes.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#76870
; Package
emacs
.
(Sun, 09 Mar 2025 19:47:02 GMT)
Full text and
rfc822 format available.
Message #17 received at 76870 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
On 2025-03-09 11:39, Eli Zaretskii wrote:
>> If yes, then I find it confusing to read that Emacs could not
>> *start* the server in the resulting warning.
>
> So you want to have an alternative message about stopping only? That
> could be a good idea, yes.
Exactly. The attached patch a) stops the server in a silent way from
function `server-unload-function' and b) extends function `server-start'
to issue the following messages if an external server is running:
M-x server-start RET
[message unchanged compared to master]
⛔ Warning (server): Unable to start the Emacs server.
There is an existing Emacs server, named "server"
To start the server in this Emacs process, stop the existing server or call M-x server-force-delete to forcibly disconnect it.
C-u M-x server-start RET
⛔ Warning (server): Unable to stop an external Emacs server.
There is an existing Emacs server, named "server"
Stop it either in its Emacs session or call M-x server-force-delete to forcibly disconnect it.
Please let me know what you think.
Thanks
[0001-Improve-message-handling-on-server-stop.patch (text/x-patch, attachment)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#76870
; Package
emacs
.
(Sun, 09 Mar 2025 19:56:01 GMT)
Full text and
rfc822 format available.
Message #20 received at 76870 <at> debbugs.gnu.org (full text, mbox):
> Date: Sun, 9 Mar 2025 20:46:27 +0100
> Cc: 76870 <at> debbugs.gnu.org
> From: Jens Schmidt <jschmidt4gnu <at> vodafonemail.de>
>
>
> C-u M-x server-start RET
>
> ⛔ Warning (server): Unable to stop an external Emacs server.
How do you know it is an "external" server process? Stopping the
server could fail for a variety of reasons, and I don't think we
should confuse the user with our guesses, except if we present that as
a guess. So something like
⛔ Warning (server): Unable to stop the server.
The existing Emacs server, called "server", could not be stopped.
(Perhaps it was run from a different Emacs session?)
You can try stopping the server forcibly by calling M-x server-force-delete.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#76870
; Package
emacs
.
(Sun, 09 Mar 2025 21:19:02 GMT)
Full text and
rfc822 format available.
Message #23 received at 76870 <at> debbugs.gnu.org (full text, mbox):
On 2025-03-09 20:54, Eli Zaretskii wrote:
> How do you know it is an "external" server process?
Because
a) the only condition handled by the condition-case
in `server-start´ (with and without my patch) is
named `server-running-external';
b) the only body form of the condition-case that
could signal something seems to be the call to
`server-stop´;
c) `server-stop' only seems to signal one "explicit"
signal, namely `server-running-external';
d) and that only if there is actually an external
server process running.
Wouldn't that justify to tailor the error messages also
only to the "cannot stop external server" case?
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#76870
; Package
emacs
.
(Sat, 15 Mar 2025 11:51:03 GMT)
Full text and
rfc822 format available.
Message #26 received at 76870 <at> debbugs.gnu.org (full text, mbox):
> Date: Sun, 9 Mar 2025 22:18:08 +0100
> Cc: 76870 <at> debbugs.gnu.org
> From: Jens Schmidt <jschmidt4gnu <at> vodafonemail.de>
>
> On 2025-03-09 20:54, Eli Zaretskii wrote:
>
> > How do you know it is an "external" server process?
>
> Because
>
> a) the only condition handled by the condition-case
> in `server-start´ (with and without my patch) is
> named `server-running-external';
>
> b) the only body form of the condition-case that
> could signal something seems to be the call to
> `server-stop´;
>
> c) `server-stop' only seems to signal one "explicit"
> signal, namely `server-running-external';
>
> d) and that only if there is actually an external
> server process running.
>
> Wouldn't that justify to tailor the error messages also
> only to the "cannot stop external server" case?
Maybe, but I still prefer not to second guess what exactly happens,
but just tell what we know.
Would you like submitting a patch with that nit taken care of?
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#76870
; Package
emacs
.
(Sat, 15 Mar 2025 18:27:02 GMT)
Full text and
rfc822 format available.
Message #29 received at 76870 <at> debbugs.gnu.org (full text, mbox):
On 2025-03-15 12:50, Eli Zaretskii wrote:
> Would you like submitting a patch with that nit taken care of?
Yes, but please let me clarify another nit first. With your
proposal we would have error messages like this [comments and
empty lines by me]:
- For the stop-then-restart case:
[message unchanged comapared to master]
⛔ Warning (server): Unable to start the Emacs server.
[the next line is actually generated from the caught error as `(cadr err)':]
There is an existing Emacs server, named "server"
To start the server in this Emacs process, stop the existing server or call M-x server-force-delete to forcibly disconnect it.
- For the stop-only case:
⛔ Warning (server): Unable to stop the server.
[but "your" next line I cannot generate as `(cadr err)':]
The existing Emacs server, called "server", could not be stopped.
(Perhaps it was run from a different Emacs session?)
You can try stopping the server forcibly by calling M-x server-force-delete.
However, I like "your" second line better than the existing one, to be
honest, and it would also fit the existing stop-then-restart case well.
So would you mind if I also changed function `server-stop' to always
signal according to your proposal:
(signal 'server-running-external
(list (format "The existing Emacs server, called \"%s\", could not be stopped."
server-name))))
and then use the `(cadr err)' for both cases?
(Sorry for asking, but I still routinely fail to predict your
reaction on my proposals ... :-)
Thanks.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#76870
; Package
emacs
.
(Sun, 16 Mar 2025 07:35:02 GMT)
Full text and
rfc822 format available.
Message #32 received at 76870 <at> debbugs.gnu.org (full text, mbox):
> Date: Sat, 15 Mar 2025 19:25:47 +0100
> Cc: 76870 <at> debbugs.gnu.org
> From: Jens Schmidt <jschmidt4gnu <at> vodafonemail.de>
>
> On 2025-03-15 12:50, Eli Zaretskii wrote:
>
> > Would you like submitting a patch with that nit taken care of?
>
> Yes, but please let me clarify another nit first. With your
> proposal we would have error messages like this [comments and
> empty lines by me]:
>
> - For the stop-then-restart case:
>
> [message unchanged comapared to master]
>
> ⛔ Warning (server): Unable to start the Emacs server.
>
> [the next line is actually generated from the caught error as `(cadr err)':]
> There is an existing Emacs server, named "server"
> To start the server in this Emacs process, stop the existing server or call M-x server-force-delete to forcibly disconnect it.
>
> - For the stop-only case:
>
> ⛔ Warning (server): Unable to stop the server.
>
> [but "your" next line I cannot generate as `(cadr err)':]
> The existing Emacs server, called "server", could not be stopped.
> (Perhaps it was run from a different Emacs session?)
> You can try stopping the server forcibly by calling M-x server-force-delete.
>
> However, I like "your" second line better than the existing one, to be
> honest, and it would also fit the existing stop-then-restart case well.
>
> So would you mind if I also changed function `server-stop' to always
> signal according to your proposal:
>
> (signal 'server-running-external
> (list (format "The existing Emacs server, called \"%s\", could not be stopped."
> server-name))))
>
> and then use the `(cadr err)' for both cases?
Yes, that'd be good.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#76870
; Package
emacs
.
(Sun, 23 Mar 2025 15:23:02 GMT)
Full text and
rfc822 format available.
Message #35 received at 76870 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
On 2025-03-16 08:34, Eli Zaretskii wrote:
>> So would you mind if I also changed function `server-stop' to always
>> signal according to your proposal:
>>
>> (signal 'server-running-external
>> (list (format "The existing Emacs server, called \"%s\", could not be stopped."
>> server-name))))
>>
>> and then use the `(cadr err)' for both cases?
>
> Yes, that'd be good.
I have attached two versions of the patch: The first
0001-Improve-message-handling-on-server-stop.patch
with the messages we have agreed upon so far:
Restart-then-stop:
1 ⛔ Warning (server): Unable to start the Emacs server.
2 The existing Emacs server, called "server", could not be stopped.
3 To start the server in this Emacs process, stop the existing server or call M-x server-force-delete to forcibly disconnect it.
Stop-only:
4 ⛔ Warning (server): Unable to stop the server.
5 The existing Emacs server, called "server", could not be stopped.
6 (Perhaps it was run from a different Emacs session?)
7 You can try stopping the server forcibly by calling M-x server-force-delete.
The second one
0001-Improve-message-handling-on-server-stop-consistent.patch
fixes (IMO) two minor inconsistencies ("server" vs. "Emacs server"
in line 4, "Emacs process" vs. "Emacs session" in line 3):
Restart-then-stop:
1 ⛔ Warning (server): Unable to start the Emacs server.
2 The existing Emacs server, called "server", could not be stopped.
3 To start the server in this Emacs session, stop the existing server or call M-x server-force-delete to forcibly disconnect it.
Stop-only:
4 ⛔ Warning (server): Unable to stop the Emacs server.
5 The existing Emacs server, called "server", could not be stopped.
6 (Perhaps it was run from a different Emacs session?)
7 You can try stopping the server forcibly by calling M-x server-force-delet
If one of these is OK for you (I'd prefer the second one), please
go ahead and install them, otherwise please let me know what still
needs fixing.
Thanks!
[0001-Improve-message-handling-on-server-stop.patch (text/x-patch, attachment)]
[0001-Improve-message-handling-on-server-stop-consistent.patch (text/x-patch, attachment)]
Reply sent
to
Eli Zaretskii <eliz <at> gnu.org>
:
You have taken responsibility.
(Sat, 29 Mar 2025 10:46:02 GMT)
Full text and
rfc822 format available.
Notification sent
to
Jens Schmidt <jschmidt4gnu <at> vodafonemail.de>
:
bug acknowledged by developer.
(Sat, 29 Mar 2025 10:46:02 GMT)
Full text and
rfc822 format available.
Message #40 received at 76870-done <at> debbugs.gnu.org (full text, mbox):
> Date: Sun, 23 Mar 2025 16:22:08 +0100
> Cc: 76870 <at> debbugs.gnu.org
> From: Jens Schmidt <jschmidt4gnu <at> vodafonemail.de>
>
> On 2025-03-16 08:34, Eli Zaretskii wrote:
>
> >> So would you mind if I also changed function `server-stop' to always
> >> signal according to your proposal:
> >>
> >> (signal 'server-running-external
> >> (list (format "The existing Emacs server, called \"%s\", could not be stopped."
> >> server-name))))
> >>
> >> and then use the `(cadr err)' for both cases?
> >
> > Yes, that'd be good.
>
> I have attached two versions of the patch: The first
>
> 0001-Improve-message-handling-on-server-stop.patch
>
> with the messages we have agreed upon so far:
>
> Restart-then-stop:
>
> 1 ⛔ Warning (server): Unable to start the Emacs server.
> 2 The existing Emacs server, called "server", could not be stopped.
> 3 To start the server in this Emacs process, stop the existing server or call M-x server-force-delete to forcibly disconnect it.
>
> Stop-only:
>
> 4 ⛔ Warning (server): Unable to stop the server.
> 5 The existing Emacs server, called "server", could not be stopped.
> 6 (Perhaps it was run from a different Emacs session?)
> 7 You can try stopping the server forcibly by calling M-x server-force-delete.
>
> The second one
>
> 0001-Improve-message-handling-on-server-stop-consistent.patch
>
> fixes (IMO) two minor inconsistencies ("server" vs. "Emacs server"
> in line 4, "Emacs process" vs. "Emacs session" in line 3):
>
> Restart-then-stop:
>
> 1 ⛔ Warning (server): Unable to start the Emacs server.
> 2 The existing Emacs server, called "server", could not be stopped.
> 3 To start the server in this Emacs session, stop the existing server or call M-x server-force-delete to forcibly disconnect it.
>
> Stop-only:
>
> 4 ⛔ Warning (server): Unable to stop the Emacs server.
> 5 The existing Emacs server, called "server", could not be stopped.
> 6 (Perhaps it was run from a different Emacs session?)
> 7 You can try stopping the server forcibly by calling M-x server-force-delet
>
> If one of these is OK for you (I'd prefer the second one), please
> go ahead and install them, otherwise please let me know what still
> needs fixing.
Thanks, I installed the second one on the master branch.
Closing.
This bug report was last modified 14 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.