Version 1.3 of ais/ai-00371.txt

Unformatted version of ais/ai-00371.txt version 1.3
Other versions for file ais/ai-00371.txt

!standard A.18          04-02-05 AI95-00371/01
!class amendment 03-12-30
!status No Action (6-1-3) 04-03-05
!status work item 03-12-30
!status received 03-12-30
!priority Medium
!difficulty Medium
!subject New hierarchy for OS-dependent services
!summary
A new root package for language defined units is added to the language. It contains information about the underlying operating system, and its descendents are assumed to provide operating-system dependent operations.
!problem
Currently, children of Ada are units whose definition does not depend on the target system, and children of System are units whose definition has dependencies on the hardware. There is no hierachy for units that depend on the host operating system. There was only one of these (Command_Line) in Ada95, but more such units are bound to appear in Ada05 (Directories, possibly others).
!proposal
Add a new package named "OS" to serve as the root of OS-dependent services. It is understood that part of the semantics of the units rooted at OS can have variations according to the underlying operating system.
Packages that fall under this definition (Command_Line, Directories) are made children of OS.
Moreover, packages providing access to commonly found services of operating systems, like environment variables and process execution, are proposed.
!wording
The following package exists:
package OS is function OS_Name return String; function OS_Version return String;
Unsupported : exception; end OS;
Both OS_Name and OS_Version return implementation-defined strings, with lower bound of 1. The string returned by OS_Name should not change when the underlying operating system changes version. The string returned by OS_Version should change when the underlying operating system changes version.
The exception Unsupported is raised by subprograms in this package or its children whenever an operation cannot be provided by the operating system.
Packages Command_Line and Directories are children of OS, i.e. they are named OS.Command_Line and OS.Directories. The following renaming exists:
with OS.Command_Line; package Ada.Command_Line renames OS.Command_Line;
The following package exists:
package Environment is procedure Set_Variable (Name : String; To : String); function Get_Variable (Name : String) return String; function Path return String;
function Locate_Executable (Name : String) return String; function Locate_Regular_File (Name : String; Path : String := "") return String; end Environment;
This package provides access to environment variables. An environment variable is a value external to the program, which has a name.
If the operating system does not support the notion of environment variables, calls to Get_Variable will always return the null string, and calls to Set_Variable will raise Unsupported.
The function Path returns an implementation defined string which defines the location of executable files. If the operating system does not support the notion of path, the null string is returned.
The function Locate_Executable returns a string corresponding to the full name of the specified executable name, following the operating system's conventions for locating executables. The exception Ada.IO_Exceptions.Name_Error is raised if no executable with the given name can be identified.
The function Locate_Regular_File returns a string corresponding to the full name of the specified file name, following the operating system's conventions for locating data files. The exception Ada.IO_Exceptions.Name_Error is raised if no file with the given name can be identified.
The following package exists:
with OS.Command_Line; package Processes is type Process_ID is private; Null_Process_ID : constant Process_ID;
procedure Spawn (Command : in String; Parameters : in String := ""; Result : out OS.Command_Line.Exit_Status); function Non_Blocking_Spawn (Command : in String; Parameters : in String = "") return Process_ID;
procedure Execute(Command_Line : in String; Result : out OS.Command_Line.Exit_Status); function Non_Blocking_Execute (Command_Line : in String; Result : out OS.Command_Line.Exit_Status) return Process_ID;
procedure Wait_Process (Pid : in Process_Id; Result : out OS.Command_Line.Exit_Status); procedure Wait_Any_Process (Pid : out Process_Id; Result : out OS.Command_Line.Exit_Status);
No_Such_Pid : exception;
private -- Not specified by the language end Processes;
A value of the type Process_ID identifies a subprocess, as started by the Spawn, Non_Blocking_Spawn, Execute and Non_Blocking_Execute subprograms in this package. The constant Null_Process_ID does not identify any process. Each object of the type Process_ID is default initialized to the value Null_Process_ID.
The procedure Spawn starts a new process, executing the executable whose name is given as Command, with a parameter string given by Parameters. It blocks until the process terminates. The exit status of the process is returned in Result. It is implementation defined if the name given in Command is subject to the rules for finding executables. If the process could not be started (for example because Command does not identify an executable, of for OS dependent reasons), Failure is returned in Result.
The procedure Non_Blocking Spawn starts a new process, executing the executable whose name is given as Command, with a parameter string given by Parameters. It blocks until the process has started, and returns the Process_IO of the child process. If the process could not be started (for example because Command does not identify an executable, of for OS dependent reasons), Null_Task_ID is returned.
The subprograms Execute and Non_Blocking_Execute behave like Spawn and Non_Blocking_Spawn respectively, except that the process is started by a string given as the Command_Line parameter, with the syntax of Shell commands appropriate to the operating system. The syntax of the Command_Line parameter is implementation defined. On operating systems where it makes sense, it is expected that the process is started as a shell command.
The procedure Wait_Process blocks until the process specified by Pid has terminated. The exit status of the process is returned in Result. If Pid is Null_Pid, or identifies a process for which Wait_Process has already been called, or which has been already returned by Wait_Any_Process, the exception No_Such_Pid is raised.
The procedure Wait_Any_Process blocks until one of the processes previously started by one of the Non_Blocking_Spawn or Non_Blocking_Execute procedures has terminated. The exit status of the process is returned in Result. If Pid is Null_Pid, or there is no more process to wait for, the exception No_Such_Pid is raised.
Implementation requirement
The implementation of Wait_Process must be task safe in the following sense: if two tasks call Wait_Process simultaneously on the same Pid, one of them receives No_Such_Pid, and the other one behaves as specified. Which task receives the exception is implementation defined.
The implementation of Wait_Any_Process must be task safe in the following sense: if two tasks call Wait_Any_Process simultaneously, they will never receive the same Pid.
!discussion
OS_Version is often referred to as one or two numbers, like major version number and minor version number. But all operating systems do not necessarily follow this convention, and there are sometimes variants, like in 3.2a. Providing a string that can be parsed if necessary seemed the most general solution.
!example
--!corrigendum
!ACATS test
!appendix

From: Randy Brukardt
Sent: Thursday, February 5, 2004  10:12 PM

A couple of comments on this proposal (now AI-371).

...
> Currently, children of Ada are units whose definition does not depend on
> the target system, and children of System are units whose definition has
> dependencies on the hardware.

I don't see where you get this statement from. The existence of Command_Line
certainly says it's not true, but even ignoring Command_Line, claiming that
any of the IO packages "do not depend on the target system" requires an
amazing stretch of imagination.

> There is no hierachy for units that depend on the host operating system.
> There was only one of these (Command_Line) in Ada95, but more such units
> are bound to appear in Ada05 (Directories, possibly others).

Certainly Directories belongs with the other IO packages! It's all about
manipulating file names - it's pretty useless without being able to do
something with the names afterwards.

> !proposal
>
> Add a new package named "OS" to serve as the root of OS-dependent
> services. It is understood that part of the semantics of the units
> rooted at OS can have variations according to the underlying operating
> system.

Creating new top-level packages is exactly what the Ada root was intended to
avoid. With this proposal, any program that has a package named OS is
instantantly unable to use Ada 200Y.

Children of Ada are essentially reserved for the Standard (and to a lesser
extent, implementers) to use, so adding new packages there is much less to
cause harm. (And we can fairly quickly find  out about any conflicts.)

Moreover, the proposed name implies that an operating system is present, but
certainly at least some of the facilities can make useful sense without one
(on a bare-machine implementation of Ada).

Finally, there doesn't seem to be enough contents in this hierarchy to
justify a new root. Just put the additional packages into Ada.

---

The Environment package was also proposed by David Wheeler via SIGAda (see
AI-370), so I expect that we'll end up discussing it in the context of that
AI. I don't much like either proposal, for different reasons, but if I had
to choose one, I'd prefer this one. But, in any case, the functionality is
useful (this was the third of the three "packages to standardize" that I
identified when we started the amendment process - I never had enough energy
to propose one.

Spawn functionality makes sense. I'm not sure I'd go as far as this package
does (we just provide Spawn, with a non-blocking flag, and a Wait for the
non-blocking version; Execute is interesting, but very hard to implement
portably on Windows).

****************************************************************

From: Jean-Pierre Rosen
Sent: Wednesday, February 11, 2004  11:02 AM

> > Currently, children of Ada are units whose definition does not depend on
> > the target system, and children of System are units whose definition has
> > dependencies on the hardware.
>
> I don't see where you get this statement from. The existence of Command_Line
> certainly says it's not true, but even ignoring Command_Line, claiming that
> any of the IO packages "do not depend on the target system" requires an
> amazing stretch of imagination.

Lawier's hat off, I'm talking about the point of view of the casual user. If
you are porting a program, you know that modules that do not depend on System
or its children should not have (much) portability problems (OK,  I know,
except for dependencies on predefined types, and the syntax of file names in IO
packages). Of course, *bodies* of packages in the Ada hierarchy depend on the
OS, but that's a different issue.

> Certainly Directories belongs with the other IO packages! It's all about
> manipulating file names - it's pretty useless without being able to do
> something with the names afterwards.

I absolutely do not agree that Directories is an IO package. You can imagine a
lot of utilities, including the one I mentionned in my previous message, that
play with files and copy and rename them without ever opening them.

> Creating new top-level packages is exactly what the Ada root was intended to
> avoid. With this proposal, any program that has a package named OS is
> instantantly unable to use Ada 200Y.
>
> Children of Ada are essentially reserved for the Standard (and to a lesser
> extent, implementers) to use, so adding new packages there is much less to
> cause harm. (And we can fairly quickly find  out about any conflicts.)

That's a good point, I do not object to have it as Ada.OS instead.

> Moreover, the proposed name implies that an operating system is present, but
> certainly at least some of the facilities can make useful sense without one
> (on a bare-machine implementation of Ada).

If you intend to manipulate files or environment variables, you certainly have
some kind of OS lying around (my definition of OS includes real-time kernels).
If it's really a bare-machine, these packages are inapplicable anyway.

> Finally, there doesn't seem to be enough contents in this hierarchy to
> justify a new root. Just put the additional packages into Ada.

Why do we have Ada.Numerics then? The situation is quite similar.

> ---
>
> The Environment package was also proposed by David Wheeler via SIGAda (see
> AI-370), so I expect that we'll end up discussing it in the context of that
> AI. I don't much like either proposal, for different reasons, but if I had
> to choose one, I'd prefer this one. But, in any case, the functionality is
> useful (this was the third of the three "packages to standardize" that I
> identified when we started the amendment process - I never had enough energy
> to propose one.
>
> Spawn functionality makes sense. I'm not sure I'd go as far as this package
> does (we just provide Spawn, with a non-blocking flag, and a Wait for the
> non-blocking version; Execute is interesting, but very hard to implement
> portably on Windows).

I needed Execute on Windows because of the difference between internal and
external commands. Also, Spawn will typically not use the Path to find
executables, while Execute will. Implementing Execute requires to know whether
the interpreter is called COMMAND.COM or CMD.EXE, but that's not too hard to
find out. See my OS_Services package.

****************************************************************

From: Randy Brukardt
Sent: Wednesday, February 11, 2004  3:37 PM

> > Certainly Directories belongs with the other IO packages! It's all about
> > manipulating file names - it's pretty useless without being able to do
> > something with the names afterwards.
>
> I absolutely do not agree that Directories is an IO package. You
> can imagine a lot of utilities, including the one I
> mentionned in my previous message, that play with files and copy
> and rename them without ever opening them.

I view files as an artifact of I/O, and manipulating them as an I/O
function -- even if you're manipulating the results of someone else's I/O.
In any case, files are a well understood part of Ada, and that part of Ada
is rooted at "Ada". Putting part of that functionality in some other
hierarchy would be artificially dividing it.

It's unfortunate that Ada 95 didn't define a package IO with children of
Text, Direct, etc., (and of course Directories) but it's clearly too late
for that now. (As I recall, it was considered, but thought to be too
radical.)

> > Finally, there doesn't seem to be enough contents in this hierarchy to
> > justify a new root. Just put the additional packages into Ada.
>
> Why do we have Ada.Numerics then? The situation is quite similar.

Ada.Numerics contains 7 packages in Ada 95, and will contain (2?) more in
Ada 0Y. Your proposed Ada.OS contains two new packages and one old one, for
a total of 3. That doesn't seem like enough, especially for the disruption
of moving one.

> > Spawn functionality makes sense. I'm not sure I'd go as far as this package
> > does (we just provide Spawn, with a non-blocking flag, and a Wait for the
> > non-blocking version; Execute is interesting, but very hard to implement
> > portably on Windows).
>
> I needed Execute on Windows because of the difference between
> internal and external commands. Also, Spawn will typically
> not use the Path to find executables, while Execute will.
> Implementing Execute requires to know whether the interpreter is
> called COMMAND.COM or CMD.EXE, but that's not too hard
> to find out. See my OS_Services package.

That depends. If you are trying to use the current user's shell, then
finding it is quite a bit more difficult than simply deciding what system
you are running on. That's especially important when they are running an
updated version of the shell processor -- you don't want to use the old one.
And I'm pretty sure that you can't assume that it is on the path; you have
to use other means to find it. (The path is obsolete for Windows anyway.) As
I recall, there are at least four different ways to find the command
processor, and none of them are general.

If you're trying to find the "standard" shell, then you have to define what
that means. (Else there would be no portability at all, and then there is no
point of it being in the standard.) It's obvious enough for Windows
(although getting the correct executable can be interesting on a system that
has been upgraded, as older versions can still be around), but what does it
mean on Unix? Bourne shell, C shell, Korn shell?? It matters, of course,
because these have different syntax. And not all systems even have all
three.

So I don't think it is worth the effort to define this (even if it is useful
on Windows). But I don't feel strongly about that.

****************************************************************

From: Jean-Pierre Rosen
Sent: Thursday, February 12, 2004  3:02 AM

Randy said:
> I view files as an artifact of I/O, and manipulating them as an I/O
> function -- even if you're manipulating the results of someone else's I/O.
> In any case, files are a well understood part of Ada, and that part of Ada
> is rooted at "Ada". Putting part of that functionality in some other
> hierarchy would be artificially dividing it.

Our view differs on this. I don't think it's worth wasting bandwidth discussing
between us about that. Maybe a strawpoll from the others?

> It's unfortunate that Ada 95 didn't define a package IO with children of
> Text, Direct, etc., (and of course Directories) but it's clearly too late
> for that now. (As I recall, it was considered, but thought to be too
> radical.)
Agreed.

> Ada.Numerics contains 7 packages in Ada 95, and will contain (2?) more in
> Ada 0Y. Your proposed Ada.OS contains two new packages and one old one, for
> a total of 3. That doesn't seem like enough, especially for the disruption
> of moving one.

Moving is not a big disruption. We did that for Text_IO, and I never heard
anybody complaining about that. OTOH, Ada.OS would be a place to attract more
packages of the kind - possibly defined by IWA - in addition to the standard.


> > > Spawn functionality makes sense. I'm not sure I'd go as far as this package
> > > does (we just provide Spawn, with a non-blocking flag, and a Wait for the
> > > non-blocking version; Execute is interesting, but very hard to implement
> > > portably on Windows).
> > >
> > I needed Execute on Windows because of the difference between
> > internal and external commands. Also, Spawn will typically
> > not use the Path to find executables, while Execute will.
> > Implementing Execute requires to know whether the interpreter is
> > called COMMAND.COM or CMD.EXE, but that's not too hard
> > to find out. See my OS_Services package.
>
> That depends. If you are trying to use the current user's shell, then
> finding it is quite a bit more difficult than simply deciding what system
> you are running on. [...]

> If you're trying to find the "standard" shell, then you have to define what
> that means. (Else there would be no portability at all, and then there is no
> point of it being in the standard.) [...]

The idea of the Ada.OS hierarchy is to warn the user that there can be OS
related non portabilities with these packages, so I don't think that perfect
portability is a major issue here.

Imagine this dialog:
User:  I want to add a command in my Windows program allowing to execute any
       command as if given from the command line.
Lawier: Well, you can't do that, because it would not be 100% portable to Linux
User:  But I said it was a WINDOWS program !!!

To me making something reasonably sensible is enough. That means, use
COMMAND.COM on Win9X, CMD.EXE on the Win/NT family, and sh on Unix systems. I
know, you may have a Linux system without sh. I'll bet you'll have so many
trouble that you would quickly add it.

****************************************************************

From: Robert A. Duff
Sent: Thursday, February 12, 2004  8:31 AM

> Our view differs on this. I don't think it's worth wasting bandwidth
> discussing between us about that.
> Maybe a strawpoll from the others?

I've lost track of what you two were arguing about.  Is it "Are
directory operations I/O?"  Yes, of course they are -- at least some of
them.  Calendar.Clock is I/O, too, and it was a design mistake to put it
in the same package as conceptually pure stuff like day/month/year
calculations.  Or was it about the package name?  (I don't much care.)

> The idea of the Ada.OS hierarchy is to warn the user that there can be
> OS related non portabilities with these packages,
> so I don't think that perfect portability is a major issue here.
> Imagine this dialog:
> User:  I want to add a command in my Windows program allowing to
> execute any command as if given from the command line.
> Lawier: Well, you can't do that, because it would not be 100% portable
> to Linux
> User:  But I said it was a WINDOWS program !!!

I don't know whether I'm for or against this feature, but we've seen the
above kind of thing before (you can't have X, because of Y -- but the
user has no interest in using Y).  Pretty frustrating for users.

> To me making something reasonably sensible is enough. That means, use
> COMMAND.COM on Win9X, CMD.EXE on the Win/NT
> family, and sh on Unix systems. I know, you may have a Linux system
> without sh. I'll bet you'll have so many trouble
> that you would quickly add it.

I believe 'sh' exists on all Unix systems.

I believe both Unix and (at least some flavors of) Windows have some way
for the user to define the desired command processor.  Environment
variables, /etc/passwd, whatever.  Should such things be used?
On my Windows XP system, I might want it to use Cygwin's tcsh.

****************************************************************

From: Peter Hermann
Sent: Thursday, February 12, 2004  4:05 AM

> Moving is not a big disruption.
> We did that for Text_IO, and I never heard anybody complaining about that.

supported with useful simple renames on the standard side.

> The idea of the Ada.OS hierarchy is to warn the user
> that there can be OS related non portabilities with these packages,

As soon as there appears a "With System;" a program is by definition
non-portable; the same may be for ada.os ...

****************************************************************

From: Jeffrey Carter
Sent: Thursday, February 12, 2004  6:29 PM

with System;
procedure Whatever is
    type T is digits System.Max_Digits;

Completely portable; the program uses the maximum precision available on
the target.

****************************************************************

From: Peter Hermann
Sent: Friday, February 13, 2004  3:18 AM

not "completely".
depends on the viewpoint:
compile time: yes ( sometimes ;-) ).
run time: if and only if your code adapts to specific constraints.

****************************************************************

From: Randy Brukardt
Sent: Thursday, February 12, 2004  2:43 PM

> I've lost track of what you two were arguing about.  Is it "Are
> directory operations I/O?"

Yes. Jean-Pierre said that Ada.Directories is belongs in his Ada.OS
hierarchy. I said it belongs with I/O, because its about manipulating files
and file names - which is what Text_IO, Direct_IO, etc. are about. It would
be weird to put them in different places - and they have about the same
level of system-dependency. In Ada's case, I/O is directly in "Ada".

> Yes, of course they are -- at least some of
> them.  Calendar.Clock is I/O, too, and it was a design mistake to put it
> in the same package as conceptually pure stuff like day/month/year
> calculations.

Sounds like you agree with me.

> > The idea of the Ada.OS hierarchy is to warn the user that there can be
> > OS related non portabilities with these packages,
> > so I don't think that perfect portability is a major issue here.
> > Imagine this dialog:
> > User:  I want to add a command in my Windows program allowing to
> > execute any command as if given from the command line.
> > Lawier: Well, you can't do that, because it would not be 100% portable
> > to Linux
> > User:  But I said it was a WINDOWS program !!!
>
> I don't know whether I'm for or against this feature, but we've seen the
> above kind of thing before (you can't have X, because of Y -- but the
> user has no interest in using Y).  Pretty frustrating for users.

I certainly agree with that sentiment as well. And I don't think anyone is
arguing that we shouldn't support things that are useful on most systems.

I'm not necessarily against the proposal, I simply don't know what it does.
And the exchange about is misleading, because I wasn't talking about
portability between Windows and Linux (for example), I was talking about
portability between various versions of Windows.

> > To me making something reasonably sensible is enough. That means, use
> > COMMAND.COM on Win9X, CMD.EXE on the Win/NT
> > family, and sh on Unix systems.

That's definitely not what I imagined reading the description of the
facility. If that's what you want (use the *standard* command processor, as
opposed to the *current* command processor), I think you need to say that,
and then add an AARM note that says the above.

...
> I believe both Unix and (at least some flavors of) Windows have some way
> for the user to define the desired command processor.  Environment
> variables, /etc/passwd, whatever.  Should such things be used?
> On my Windows XP system, I might want it to use Cygwin's tcsh.

Right. And that was my point. If you do that, then the program isn't even
portable between different Windows machines (who knows what's installed??).
(It's also hard to implement.) So that seems like a bad idea.

Jean-Pierre seems to be proposing instead that the *standard* command
processor be used. What he doesn't seem to explain is how you might find
such a thing. On Windows, at least, the path is obsolete (and thus may not
point at anything at all), and searching the user's disk for "COMMAND.COM"
or "CMD.EXE" is not something that you want to do for every call to
"Execute"!

****************************************************************

From: Jean-Pierre Rosen
Sent: Friday, February 13, 2004  4:29 AM

From: "Randy Brukardt" <randy@rrsoftware.com>
> > > To me making something reasonably sensible is enough. That means, use
> > > COMMAND.COM on Win9X, CMD.EXE on the Win/NT
> > > family, and sh on Unix systems.
>
> That's definitely not what I imagined reading the description of the
> facility. If that's what you want (use the *standard* command processor, as
> opposed to the *current* command processor), I think you need to say that,
> and then add an AARM note that says the above.
The main issue is that (crazy) notion of "internal" commands. I want to be sure
that a "copy" under Windows works! I you ask me to improve the proposal, I'd be
happy to do that. As soon as the ARG decides  that the proposal is worth
considering, and I'm given a homework...

> Jean-Pierre seems to be proposing instead that the *standard* command
> processor be used. What he doesn't seem to explain is how you might find
> such a thing. On Windows, at least, the path is obsolete (and thus may not
> point at anything at all), and searching the user's disk for "COMMAND.COM"
> or "CMD.EXE" is not something that you want to do for every call to
> "Execute"!
I guess that if you consider PATH obsolete, you would consider COMPATH (or is
it ComSpec?) to be obsolete too... I'd say that these are the kind of obsolete
things that will stay forever. Anyway, if you don't find COMMAND.COM or
CMD.EXE, you raise an Unsupported exception, that's all.

****************************************************************

From: Randy Brukardt
Sent: Friday, February 13, 2004 10:04 PM

> The main issue is that (crazy) notion of "internal" commands. I
> want to be sure that a "copy" under Windows works!

Fair enough. Of course, you don't need Copy -- use Ada.Directories.Copy_File
for that (possibly combined with a directory search - Copy_File isn't going
to support wildcards). But there may be other commands that you do need.

> I you ask me to improve the proposal, I'd be happy to do that. As
> soon as the ARG decides  that the proposal is worth
> considering, and I'm given a homework...

I would expect that AI-371 will be on the agenda for Phoenix.

...
> I guess that if you consider PATH obsolete, you would consider
> COMPATH (or is it ComSpec?) to be obsolete too...

I have no idea whether Comspec is obsolete. Path is obsolete because
Microsoft says it is. Microsoft's documentation has recommended other ways
of finding files for years, and indeed to get the Microsoft compatibility
seal, you can't use the Path at all. Thus, few (if any) modern programs use
it.

In any case, Comspec won't necessarily point to CMD.EXE or COMMAND.COM (if,
as Bob suggested, someone is running an alternate shell). I suspect I'd try
that first, but it isn't there, I don't know. I believe there are four
different ways to find the command shell, and none of them work all the
time.

****************************************************************

From: Jean-Pierre Rosen
Sent: Friday, February 13, 2004  4:15 AM

> supported with useful simple renames on the standard side.

Which would apply equally to Command_Line.

> > The idea of the Ada.OS hierarchy is to warn the user
> > that there can be OS related non portabilities with these packages,
>
> As soon as there appears a "With System;" a program is by definition
> non-portable; the same may be for ada.os ...

I would not object to having it as System.OS

****************************************************************

From: Robert C. Leif
Sent: Saturday, February 14, 2004  3:40 PM

Where do we find AI-371?
Thank you.

****************************************************************

From: Randy Brukardt
Sent: Saturday, February 14, 2004  7:08 PM

I haven't posted it yet. But the original proposal was posted here at the
end of December, so you could find it by requesting the mailing to send you
messages from December 30th. Or you can wait for me to post it (I'll
probably do that next week).

****************************************************************


Questions? Ask the ACAA Technical Agent