comp.lang.ada
 help / color / mirror / Atom feed
* generic imports?  void* -> generics?
@ 2003-09-19 19:20 chris
  2003-09-19 20:46 ` chris
                   ` (3 more replies)
  0 siblings, 4 replies; 15+ messages in thread
From: chris @ 2003-09-19 19:20 UTC (permalink / raw)


Hi,

Should the following C code be mapped to a generic?

void *lua_touserdata (Lua_State* L, int pos)



I was thinking of something like

generic
    type Userdata is private;
function to_userdata (L   : in Lua_State_Access;
                       Pos : in Index) return Userdata;

but am unsure how to complete it...  I tried

    function To_Userdata (L   : in Lua_State_Access;
                          Pos : in Index) return Userdata is
       function Lua_ToUserData (L   : in Lua_State_Access;
                                Pos : in Index) return Userdata;
       pragma Import (C, Lua_ToUserData);
    begin
       return Lua_Touserdata (L, Pos);
    end To_Userdata;

and it compiles ok, but is it right?  It looks odd to me.  Will the 
function Lua_ToUserData be imported upon instantiation of the 
To_Userdata function?



Cheers,
Chris




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: generic imports?  void* -> generics?
  2003-09-19 19:20 generic imports? void* -> generics? chris
@ 2003-09-19 20:46 ` chris
  2003-09-19 21:18 ` Nick Roberts
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 15+ messages in thread
From: chris @ 2003-09-19 20:46 UTC (permalink / raw)


Another problem is that in this case the void* is a pointer to some data 
block... but if we define the following


with Lua_Types;                use Lua_Types;

generic
    type Userdata is private;
    type Userdata_Access is access all Userdata;

function Lua.To_Userdata (L   : in Lua_State_Access;
                           Pos : in Index) return Userdata_Access;

what will the interaction be with the c code?  It's not possible afaik 
to define the convention of Userdata_Access to C.

Can anyone please help?  I'm not really sure what the solution should be...

http://www.lua.org/manual/5.0/manual.html#3.8 describes the operation of 
this function ...


"lua_touserdata (see 3.5) retrieves the value of a userdata. When 
applied on a full userdata, it returns the address of its block; when 
applied on a light userdata, it returns its pointer; when applied on a 
non-userdata value, it returns NULL."




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: generic imports?  void* -> generics?
  2003-09-19 19:20 generic imports? void* -> generics? chris
  2003-09-19 20:46 ` chris
@ 2003-09-19 21:18 ` Nick Roberts
  2003-09-19 23:12   ` chris
  2003-09-20 16:52   ` Simon Wright
  2003-09-19 22:40 ` Matthew Heaney
  2003-09-23 22:39 ` chris
  3 siblings, 2 replies; 15+ messages in thread
From: Nick Roberts @ 2003-09-19 21:18 UTC (permalink / raw)


"chris" <spamoff.danx@ntlworld.com> wrote in message
news:FBIab.3309$DM5.35123@newsfep4-glfd.server.ntli.net...

> Should the following C code be mapped to a generic?
>
> void *lua_touserdata (Lua_State* L, int pos)

Not directly. I would suggest that you take the following approach.

   package Stream_C_Pointers is new Interfaces.C.Pointers(
      Index => Ada.Streams.Stream_Element_Offset,
      Element => Ada.Streams.Stream_Element,
      Element_Array => Ada.Streams.Stream_Element_Array );

   subtype Stream_C_Pointer is Stream_C_Pointers.Pointer;
   use Stream_C_Pointers;

   function LUA_To_User_Data (State: access LUA_State;
                                  Pos: Interfaces.C.int) returns
Stream_C_Pointer;

   pragma Import(C,LUA_To_User_Data,"lua_touserdata");

The general idea is that Ada code is able to read a variable from the memory
area returned by this C function, interpreted as a stream array so that the
variable's stream-oriented Read procedure or Input function can be used
directly. There could well be difficulties associated with writing data
using C code and then reading it using (stream-oriented) Ada code.

You may well wish to wrap all this up in a package or a generic package, at
a higher level of organisation.

Hope this helps. I'd be happy to give more detail if you wish.

--
Nick Roberts
Jabber: debater@charente.de [ICQ: 159718630]





^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: generic imports?  void* -> generics?
  2003-09-19 19:20 generic imports? void* -> generics? chris
  2003-09-19 20:46 ` chris
  2003-09-19 21:18 ` Nick Roberts
@ 2003-09-19 22:40 ` Matthew Heaney
  2003-09-19 23:01   ` chris
  2003-09-20  1:59   ` Jeffrey Carter
  2003-09-23 22:39 ` chris
  3 siblings, 2 replies; 15+ messages in thread
From: Matthew Heaney @ 2003-09-19 22:40 UTC (permalink / raw)


chris <spamoff.danx@ntlworld.com> writes:

> void *lua_touserdata (Lua_State* L, int pos)

I prefer thin bindings, so you just do it this way:

   function lua_touserdata
     (L   : Lua_State_Access;
      Pos : C.int) return System.Address;

   pragma Import (C, lua_touserdata);
   pragma Convention (C, lua_touserdata);

There's no binding to C type void* in Interfaces.C, but type
System.Address should work OK.  That way you can say:

   Get_MyUserData:
   declare
      Data : MyUserData_Type;
      for Data'Address use lua_touserdata(L, Pos);
   begin
      ... -- manipulate Data as appropriate
   end Get_MyUserData;

I suppose you could wrap this in a generic, which is implemented using
the function above.


> I was thinking of something like
> 
> generic
>     type Userdata is private;
> function to_userdata (L   : in Lua_State_Access;
>                        Pos : in Index) return Userdata;
> 
> but am unsure how to complete it...  I tried
> 
>     function To_Userdata (L   : in Lua_State_Access;
>                           Pos : in Index) return Userdata is
>        function Lua_ToUserData (L   : in Lua_State_Access;
>                                 Pos : in Index) return Userdata;
>        pragma Import (C, Lua_ToUserData);
>     begin
>        return Lua_Touserdata (L, Pos);
>     end To_Userdata;
> 
> and it compiles ok, but is it right?  It looks odd to me.  Will the
> function Lua_ToUserData be imported upon instantiation of the
> To_Userdata function?


This is wrong, because your Ada function to_userdata returns an object,
not a pointer to object, as the C function does.  You need to bind to an
access type, like this:

   function To_Userdata
     (L : lua_state_access;
      Pos : Index) return Userdata is

      type Userdata_Access is access all Userdata;
      for Userdata_Access'Storage_Size use 0;
      pragma Convention (C, Userdata_Access);

      function lua_touserdata
        (L   : Lua_State_Access;
         Pos : C.int) return Userdata_Access;  --ok now

      pragma Import (C, lua_touserdata);
      pragma Convention (C, lua_touserdata);

      Result : constant Userdata_Access :=
         lua_touserdata(L, Pos);
   begin
      return Result.all;
   end;






^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: generic imports?  void* -> generics?
  2003-09-19 22:40 ` Matthew Heaney
@ 2003-09-19 23:01   ` chris
  2003-09-20  1:59   ` Jeffrey Carter
  1 sibling, 0 replies; 15+ messages in thread
From: chris @ 2003-09-19 23:01 UTC (permalink / raw)


Matthew Heaney wrote:

> There's no binding to C type void* in Interfaces.C, but type
> System.Address should work OK.  That way you can say:

That was what I was going to do (did that in the past), but I wondered 
if there was a safer way.  I might go with it as it's simple enough to 
implement.


> This is wrong, because your Ada function to_userdata returns an object,
> not a pointer to object, as the C function does.  You need to bind to an
> access type, like this:

I changed it to use an access type in the spec, but the problem was the 
compiler rejected any attempt in the spec to specify the convention of a 
generic type.


>    function To_Userdata
>      (L : lua_state_access;
>       Pos : Index) return Userdata is
> 

snip

>       Result : constant Userdata_Access :=
>          lua_touserdata(L, Pos);
>    begin
>       return Result.all;
>    end;

Never thought of that, thanks.


Thanks,
Chris




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: generic imports?  void* -> generics?
  2003-09-19 21:18 ` Nick Roberts
@ 2003-09-19 23:12   ` chris
  2003-09-20 16:52   ` Simon Wright
  1 sibling, 0 replies; 15+ messages in thread
From: chris @ 2003-09-19 23:12 UTC (permalink / raw)


Nick Roberts wrote:

> The general idea is that Ada code is able to read a variable from the memory
> area returned by this C function, interpreted as a stream array so that the
> variable's stream-oriented Read procedure or Input function can be used
> directly. There could well be difficulties associated with writing data
> using C code and then reading it using (stream-oriented) Ada code.

That's an interesting idea!  I'll have to remember that one in future, 
thanks for that.

My understanding of Lua is that it wouldn't usually be a problem as the 
C code would probably call Ada functions to do the work on the Userdata. 
     There might be cases where that wouldn't happen but I'm not sure 
(lua will gc the userdata if it's not 'lightweight', but you can control 
how it does this through a user defined function)



Chris




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: generic imports?  void* -> generics?
  2003-09-19 22:40 ` Matthew Heaney
  2003-09-19 23:01   ` chris
@ 2003-09-20  1:59   ` Jeffrey Carter
  2003-09-20 13:52     ` Matthew Heaney
  1 sibling, 1 reply; 15+ messages in thread
From: Jeffrey Carter @ 2003-09-20  1:59 UTC (permalink / raw)


Matthew Heaney wrote:

>    function To_Userdata
>      (L : lua_state_access;
>       Pos : Index) return Userdata is
> 
>       type Userdata_Access is access all Userdata;
>       for Userdata_Access'Storage_Size use 0;
>       pragma Convention (C, Userdata_Access);
> 
>       function lua_touserdata
>         (L   : Lua_State_Access;
>          Pos : C.int) return Userdata_Access;  --ok now
> 
>       pragma Import (C, lua_touserdata);

You probably need to specify the C name:

pragma Import (C, lua_touserdata, "lua_touserdata");

>       pragma Convention (C, lua_touserdata);

This is unnecessary. Import defines the convention.

> 
>       Result : constant Userdata_Access :=
>          lua_touserdata(L, Pos);
>    begin
>       return Result.all;
>    end;

Or just

return Lua_Touserdata (L, Pos).all;

This is probably the best way to implement it; I was going to suggest 
something along these lines until I saw this. Of course, this would be a 
generic, with type Userdata the generic formal.

-- 
Jeff Carter
"You've got the brain of a four-year-old boy,
and I bet he was glad to get rid of it."
Horse Feathers
47




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: generic imports?  void* -> generics?
  2003-09-20  1:59   ` Jeffrey Carter
@ 2003-09-20 13:52     ` Matthew Heaney
  0 siblings, 0 replies; 15+ messages in thread
From: Matthew Heaney @ 2003-09-20 13:52 UTC (permalink / raw)


Jeffrey Carter <spam@spam.com> writes:

> pragma Import (C, lua_touserdata, "lua_touserdata");
> 
> >       pragma Convention (C, lua_touserdata);
> 
> This is unnecessary. Import defines the convention.

I wasn't sure about that, and I was too lazy to look it up.  Thanks for
the tip.




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: generic imports?  void* -> generics?
  2003-09-19 21:18 ` Nick Roberts
  2003-09-19 23:12   ` chris
@ 2003-09-20 16:52   ` Simon Wright
  2003-09-22 21:30     ` Randy Brukardt
  1 sibling, 1 reply; 15+ messages in thread
From: Simon Wright @ 2003-09-20 16:52 UTC (permalink / raw)


"Nick Roberts" <nickroberts@blueyonder.co.uk> writes:

> The general idea is that Ada code is able to read a variable from
> the memory area returned by this C function, interpreted as a stream
> array so that the variable's stream-oriented Read procedure or Input
> function can be used directly.

I don't understand this, your suggestion was for Stream_Element_Array
not Root_Stream_Type'Class which is needed for 'Read ..? I can see
that you could wrap a Stream_Element_Array in a Stream, in fact quite
a neat idea! This sort of thing? (would make an interesting addition
to the BCs .. or is this stuff that everybody has known for years &
I've just missed?)

with Ada.Streams;

package Stream_Wrappers is

   type Stream_Wrapper (For_Array : access Ada.Streams.Stream_Element_Array)
   is new Ada.Streams.Root_Stream_Type with private;

   function Last (Used_In : Stream_Wrapper)
     return Ada.Streams.Stream_Element_Offset;

private

   type Stream_Wrapper (For_Array : access Ada.Streams.Stream_Element_Array)
   is new Ada.Streams.Root_Stream_Type with record
      Next_Read : Ada.Streams.Stream_Element_Offset := For_Array'First;
      Next_Write : Ada.Streams.Stream_Element_Offset := For_Array'First;
   end record;

   procedure Read
     (Stream : in out Stream_Wrapper;
      Item   : out Ada.Streams.Stream_Element_Array;
      Last   : out Ada.Streams.Stream_Element_Offset);

   procedure Write
     (Stream : in out Stream_Wrapper;
      Item   : in Ada.Streams.Stream_Element_Array);

end Stream_Wrappers;



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: generic imports?  void* -> generics?
  2003-09-20 16:52   ` Simon Wright
@ 2003-09-22 21:30     ` Randy Brukardt
  2003-09-23  5:45       ` Simon Wright
  0 siblings, 1 reply; 15+ messages in thread
From: Randy Brukardt @ 2003-09-22 21:30 UTC (permalink / raw)


"Simon Wright" <simon@pushface.org> wrote in message
news:x7vd6dvierf.fsf@smaug.pushface.org...
> I don't understand this, your suggestion was for Stream_Element_Array
> not Root_Stream_Type'Class which is needed for 'Read ..? I can see
> that you could wrap a Stream_Element_Array in a Stream, in fact quite
> a neat idea! This sort of thing? (would make an interesting addition
> to the BCs .. or is this stuff that everybody has known for years &
> I've just missed?)

I can't speak for 'everybody' :-), but Claw has had a package like this for
years.

The Claw package puts the stream element array inside of the wrapper type.
(The access discriminant is interesting, but it couldn't be used on slices
or any constrained object, which would make it annoying to use.) That makes
it a buffer. Usually, it is used by 'loading' the buffer by calling Write
explicitly, then using the stream routines to read from it. (Or vice versa).

                   Randy.






^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: generic imports?  void* -> generics?
  2003-09-22 21:30     ` Randy Brukardt
@ 2003-09-23  5:45       ` Simon Wright
  2003-09-23 19:07         ` Randy Brukardt
  0 siblings, 1 reply; 15+ messages in thread
From: Simon Wright @ 2003-09-23  5:45 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> The Claw package puts the stream element array inside of the wrapper
> type.  (The access discriminant is interesting, but it couldn't be
> used on slices or any constrained object, which would make it
> annoying to use.) That makes it a buffer. Usually, it is used by
> 'loading' the buffer by calling Write explicitly, then using the
> stream routines to read from it. (Or vice versa).

Yes, I have BC.Support.Memory_Streams which is like that. No trouble
if I'm starting from an empty stream. But if I've read the data over
the network, say, I need to copy the data into the buffer .. I think
my problem is, providing too much encapsulation, which limits what
users can do with the package. If I want to

  create a streaming buffer
  read data from a socket that has to write to a stream_element_array,
    cos it's datagram-oriented, directly into the buffer

I probably have to make the buffer part of the stream visible.

The new version looks like

   package BC.Support.Array_Streams is

      type Stream_Type
        (Buffer : access Ada.Streams.Stream_Element_Array)
      is new Ada.Streams.Root_Stream_Type with private;
      --  Provides an in-memory Stream over the elements of Buffer.
      --
      --  When one of these Stream_Types is created, it is notionally
      --  empty. If Buffer is not in fact empty (perhaps it has been read
      --  from a datagram socket), use Set_Last to indicate the index of
      --  the last valid element.

      function Last (Used_In : Stream_Type)
                    return Ada.Streams.Stream_Element_Offset;
      --  Returns the index in Used_In's Stream_Element_Array of the last
      --  used element.

      procedure Set_Last (Used_In : in out Stream_Type;
                          To : Ada.Streams.Stream_Element_Offset);
      --  Sets the index of the last valid element in Used_In's
      --  Stream_Element_Array.

      procedure Reset (Stream : out Stream_Type);
      --  Clears Stream.

   private

which is going to require some care to use!


On a style issue, do you think I should make Stream_Type's Read, Write
operations (which must be present because of the derivation from
Root_Stream_Type) visible?

I ask because (in another package) I had a Controlled type with a
visible Initialize and someone mistakenly called it .. I know they
could have done anyway, but its being there in the public part of the
package tempted them.



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: generic imports?  void* -> generics?
  2003-09-23  5:45       ` Simon Wright
@ 2003-09-23 19:07         ` Randy Brukardt
  2003-09-23 20:28           ` Simon Wright
  0 siblings, 1 reply; 15+ messages in thread
From: Randy Brukardt @ 2003-09-23 19:07 UTC (permalink / raw)


"Simon Wright" <simon@pushface.org> wrote in message
news:x7vvfrkukgp.fsf@smaug.pushface.org...
> "Randy Brukardt" <randy@rrsoftware.com> writes:
>
> > The Claw package puts the stream element array inside of the wrapper
> > type.  (The access discriminant is interesting, but it couldn't be
> > used on slices or any constrained object, which would make it
> > annoying to use.) That makes it a buffer. Usually, it is used by
> > 'loading' the buffer by calling Write explicitly, then using the
> > stream routines to read from it. (Or vice versa).
>
> Yes, I have BC.Support.Memory_Streams which is like that. No trouble
> if I'm starting from an empty stream. But if I've read the data over
> the network, say, I need to copy the data into the buffer .. I think
> my problem is, providing too much encapsulation, which limits what
> users can do with the package. If I want to
>
>   create a streaming buffer
>   read data from a socket that has to write to a stream_element_array,
>     cos it's datagram-oriented, directly into the buffer
>
> I probably have to make the buffer part of the stream visible.

We didn't do that because we wanted the buffer to be able to hold any amount
of data. That requires behind-the-scenes memory allocation, and that insists
on a private type. For the short items that we were primarily concerned
about (registry, clipboard, etc.), the extra copy is not too bad.

> The new version looks like
>
>    package BC.Support.Array_Streams is
>
>       type Stream_Type
>         (Buffer : access Ada.Streams.Stream_Element_Array)
>       is new Ada.Streams.Root_Stream_Type with private;
>       --  Provides an in-memory Stream over the elements of Buffer.
>       --
>       --  When one of these Stream_Types is created, it is notionally
>       --  empty. If Buffer is not in fact empty (perhaps it has been read
>       --  from a datagram socket), use Set_Last to indicate the index of
>       --  the last valid element.
>
>       function Last (Used_In : Stream_Type)
>                     return Ada.Streams.Stream_Element_Offset;
>       --  Returns the index in Used_In's Stream_Element_Array of the last
>       --  used element.
>
>       procedure Set_Last (Used_In : in out Stream_Type;
>                           To : Ada.Streams.Stream_Element_Offset);
>       --  Sets the index of the last valid element in Used_In's
>       --  Stream_Element_Array.
>
>       procedure Reset (Stream : out Stream_Type);
>       --  Clears Stream.
>
>    private
>
> which is going to require some care to use!

I would consider providing both. This will be hard to use, because you have
to declare an aliased, unconstrained buffer to be able to match the
discriminant.

         Buf : aliased Stream_Element_Array (1..10);

won't work. Also, in many cases, you end up copying the data anyway; you
might as well use Write to do that.

> On a style issue, do you think I should make Stream_Type's Read, Write
> operations (which must be present because of the derivation from
> Root_Stream_Type) visible?

I always put overridings into the private part. A user shouldn't care
whether an operation is overridden; that's an implementation detail.

> I ask because (in another package) I had a Controlled type with a
> visible Initialize and someone mistakenly called it .. I know they
> could have done anyway, but its being there in the public part of the
> package tempted them.

It's best if the abstraction can withstand extra calls to Initialize and
Adjust; it has to withstand extra calls to Finalize (as they can happen in
abort situations).

                         Randy.






^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: generic imports?  void* -> generics?
  2003-09-23 19:07         ` Randy Brukardt
@ 2003-09-23 20:28           ` Simon Wright
  2003-09-24 18:16             ` Randy Brukardt
  0 siblings, 1 reply; 15+ messages in thread
From: Simon Wright @ 2003-09-23 20:28 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> I would consider providing both.

Yes ..

>                                  This will be hard to use, because you have
> to declare an aliased, unconstrained buffer to be able to match the
> discriminant.
> 
>          Buf : aliased Stream_Element_Array (1..10);
> 
> won't work.

Yes ..

   Buf : aliased Stream_Element_Array := (1 .. 10 => 0);

means you end up writing to the darn thing anyway. GNAT users can take
their lives in their hands & used 'Unrestricted_Access on a
non-aliased object, of course.

> > I ask because (in another package) I had a Controlled type with a
> > visible Initialize and someone mistakenly called it .. I know they
> > could have done anyway, but its being there in the public part of
> > the package tempted them.
> 
> It's best if the abstraction can withstand extra calls to Initialize
> and Adjust; it has to withstand extra calls to Finalize (as they can
> happen in abort situations).

I can see the Initialize -- not so sure how you could tell about extra
Adjusts?



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: generic imports?  void* -> generics?
  2003-09-19 19:20 generic imports? void* -> generics? chris
                   ` (2 preceding siblings ...)
  2003-09-19 22:40 ` Matthew Heaney
@ 2003-09-23 22:39 ` chris
  3 siblings, 0 replies; 15+ messages in thread
From: chris @ 2003-09-23 22:39 UTC (permalink / raw)


Hi,

I've been looking over the Lua Ref Manual and think I understand user 
data now.  Full user data is a block of memory created by Lua at the 
clients request.  The client provides the size of the block and Lua 
gives them an address to data of that size, or NULL.  It is subject to 
gc but is basically a blank canvas (with no real bounds, I expect).

Light user data is a pointer to something outside of Lua, like a ptr to 
a point or dom tree.  You give Lua the pointer to the thing, it just 
treats it's a void ptr and that's it.  It doesn't peek at what's at the 
address, delete it or whatever.

Given that, perhaps either of Matthews suggestions is appropriate for 
light user data (System.Address or the fixed generic) and use a 
System.Address or a stream orientated approach for the Full User Data or 
both?

It's late and I go back to Uni tomorrow, so I haven't really thought it 
through.


Chris




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: generic imports?  void* -> generics?
  2003-09-23 20:28           ` Simon Wright
@ 2003-09-24 18:16             ` Randy Brukardt
  0 siblings, 0 replies; 15+ messages in thread
From: Randy Brukardt @ 2003-09-24 18:16 UTC (permalink / raw)


"Simon Wright" <simon@pushface.org> wrote in message
news:x7vvfrjuu5e.fsf@smaug.pushface.org...
> "Randy Brukardt" <randy@rrsoftware.com> writes:
> > It's best if the abstraction can withstand extra calls to Initialize
> > and Adjust; it has to withstand extra calls to Finalize (as they can
> > happen in abort situations).
>
> I can see the Initialize -- not so sure how you could tell about extra
> Adjusts?

Humm, I think you're right; you can't really protect against extra Adjusts.
And they are the least likely to happen by accident (I think they can happen
only by an explicit call or compiler bug), so they're the least important to
protect.

                   Randy.






^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2003-09-24 18:16 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-09-19 19:20 generic imports? void* -> generics? chris
2003-09-19 20:46 ` chris
2003-09-19 21:18 ` Nick Roberts
2003-09-19 23:12   ` chris
2003-09-20 16:52   ` Simon Wright
2003-09-22 21:30     ` Randy Brukardt
2003-09-23  5:45       ` Simon Wright
2003-09-23 19:07         ` Randy Brukardt
2003-09-23 20:28           ` Simon Wright
2003-09-24 18:16             ` Randy Brukardt
2003-09-19 22:40 ` Matthew Heaney
2003-09-19 23:01   ` chris
2003-09-20  1:59   ` Jeffrey Carter
2003-09-20 13:52     ` Matthew Heaney
2003-09-23 22:39 ` chris

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox