* Sending Variable Length Messages with GNAT.Sockets @ 2005-05-09 10:11 markp 2005-05-09 10:39 ` Adrien Plisson 0 siblings, 1 reply; 18+ messages in thread From: markp @ 2005-05-09 10:11 UTC (permalink / raw) I am currently using GNAT.Sockets to send data via streams. A snippet of my code is is as follows: . . My_Stream_Access := GNAT.Sockets.Stream(Socket => Socket); . . Msg_Types.Msg_Header_Type'Write( My_Stream_Access, Msg_Type); This code works fine. It appears GNAT.Sockets works off a message type in this manner. My question is: What if the data type "Msg_Type" was a variable length message? Is there a way to send only "x" bytes for Msg_Type, and not the entire thing? Thanks, Mark ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Sending Variable Length Messages with GNAT.Sockets 2005-05-09 10:11 Sending Variable Length Messages with GNAT.Sockets markp @ 2005-05-09 10:39 ` Adrien Plisson 2005-05-09 11:19 ` markp 2005-05-09 11:19 ` Jeff C 0 siblings, 2 replies; 18+ messages in thread From: Adrien Plisson @ 2005-05-09 10:39 UTC (permalink / raw) markp wrote: > My question is: What if the data type "Msg_Type" was a variable length > message? Is there a way to send only "x" bytes for Msg_Type, and not > the entire thing? it depends on your requirements. if your receiver is an Ada software, use 'Output instead of 'Write, and there will be no problems. in any case, you can use 'Write, but you will have no way to tell the size of the message from the stream, unless the message itself contains its length (a pretty common case). reading variable length messages with 'Read can become really difficult. now choose the way you implement your variable length message. there are three kind of variable length types: - variant records with a discriminant - arrays - tagged types each have their pros and their cons... also, i can think of no way to send "x" bytes of a type and not the entire thing, unless writing your own stream input and output procedures. -- rien ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Sending Variable Length Messages with GNAT.Sockets 2005-05-09 10:39 ` Adrien Plisson @ 2005-05-09 11:19 ` markp 2005-05-09 11:50 ` Adrien Plisson 2005-05-09 14:30 ` John B. Matthews 2005-05-09 11:19 ` Jeff C 1 sibling, 2 replies; 18+ messages in thread From: markp @ 2005-05-09 11:19 UTC (permalink / raw) Thank you for your quick reply. Our target platforms are not Ada, so we chose to use the write. Could you tell me some place I could look to research how to write my own stream input/output routines? I could pass a byte count in with the message to be sent, but the stream calls seem to only take a type, not a length. For example, in our application code, we have a data type that can hold up an array of 512 entries, but we might only want to send the first 32, for example. We have built into the message header how many bytes there are, but Ada would know nothing about that. We are used to the traditional "address, byte count" wat of dealing with sockets Any help you could provide would be greatly appreciated. Thank you very much, Mark. ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Sending Variable Length Messages with GNAT.Sockets 2005-05-09 11:19 ` markp @ 2005-05-09 11:50 ` Adrien Plisson 2005-05-09 14:30 ` John B. Matthews 1 sibling, 0 replies; 18+ messages in thread From: Adrien Plisson @ 2005-05-09 11:50 UTC (permalink / raw) markp wrote: > Thank you for your quick reply. Our target platforms are not Ada, so we > chose to use the write. Could you tell me some place I could look to > research how to write my own stream input/output routines? i don't know of any place where you can find examples of custom read/write. you may try http://www.adapower.com/ or other ada related example enabled website. i think the first place is understanding ARM95 13.13 and all its subsections. we also discussed it a bit in "TCP/IP Sockets with GNAT.Sockets" on comp.lang.ada last week. basically, you declare one/both of the following procedure: procedure Msg_Write( Stream : access Ada.Streams.Root_Stream_Type'Class; Message : in Msg_Type); for Msg_Type'Write use Msg_Write; procedure Msg_Read( Stream : access Ada.Streams.Root_Stream_Type'Class; Message : out Msg_Type); for Msg_Type'Read use Msg_Read; (beware of the freezing rule which can lead to the unclear messages: no more representation items for type "..." defined at line ... representation item appears too late) > I could pass > a byte count in with the message to be sent, but the stream calls seem > to only take a type, not a length. For example, in our application > code, we have a data type that can hold up an array of 512 entries, but > we might only want to send the first 32, for example. We have built > into the message header how many bytes there are, but Ada would know > nothing about that. We are used to the traditional "address, byte > count" wat of dealing with sockets when writing your own procedure to write to/read from streams, you can use any other stream attributes. as such, you can first read/write the header using standard 'Read or 'Write attribute. from this you will have the size in bytes. by carefully using the 'Size attribute, you can easily find the number of entries in your message. then, you are back to the fixed size case and can read or write just what is needed. for more complicated stuffs, you can use the Read and Write procedures of type Ada.Streams.Root_Stream_Type'Class which allows you to read/write at the "Stream_Elements" level (basically the byte level). -- rien ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Sending Variable Length Messages with GNAT.Sockets 2005-05-09 11:19 ` markp 2005-05-09 11:50 ` Adrien Plisson @ 2005-05-09 14:30 ` John B. Matthews 2005-05-09 14:51 ` markp 1 sibling, 1 reply; 18+ messages in thread From: John B. Matthews @ 2005-05-09 14:30 UTC (permalink / raw) In article <1115637556.074009.113830@o13g2000cwo.googlegroups.com>, "markp" <markwork66@yahoo.com> wrote: [...] > Could you tell me some place I could look to > research how to write my own stream input/output routines? [...] > Mark. There's an excellent introduction in the _Ada_95_Rationale_ in section A.4.1, "Stream Input and Output". <http://www.adahome.com/LRM/95/Rationale/rat95html/rat95-p3-a.html#4> -- John jmatthews at wright dot edu www dot wright dot edu/~john.matthews/ ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Sending Variable Length Messages with GNAT.Sockets 2005-05-09 14:30 ` John B. Matthews @ 2005-05-09 14:51 ` markp 2005-05-09 18:49 ` Adrien Plisson 2005-05-09 19:16 ` Simon Wright 0 siblings, 2 replies; 18+ messages in thread From: markp @ 2005-05-09 14:51 UTC (permalink / raw) Thanks John. I still have a fundamental problem. I am working on legacy code in which data is defined in records (or arrays of records) which are sent in variable lengths. We use address, byte count to send the exact number of bytes. Using Streams, it seems they type has to be of Stream_element_Array. The only way I can see to send/receive these "variable" messages is to first read our message header which contains the number of bytes in the message. Then, create a Stream_Element_Array of the exact size for the next read. Then, do an unchecked conversion or a copy bytes routine to get the data into my data type for processing. Does this sound correct? Lastly, using the 'Read function on streams, am I guaranteed to block until I receive all bytes? Thanks, Mark ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Sending Variable Length Messages with GNAT.Sockets 2005-05-09 14:51 ` markp @ 2005-05-09 18:49 ` Adrien Plisson 2005-05-09 19:16 ` Simon Wright 1 sibling, 0 replies; 18+ messages in thread From: Adrien Plisson @ 2005-05-09 18:49 UTC (permalink / raw) markp wrote: > Thanks John. > > I still have a fundamental problem. I am working on legacy code in > which data is defined in records (or arrays of records) which are sent > in variable lengths. We use address, byte count to send the exact > number of bytes. Using Streams, it seems they type has to be of > Stream_element_Array. The only way I can see to send/receive these > "variable" messages is to first read our message header which contains > the number of bytes in the message. Then, create a Stream_Element_Array > of the exact size for the next read. Then, do an unchecked conversion > or a copy bytes routine to get the data into my data type for > processing. Does this sound correct? this sounds bof bof... a bit complicated... since you seem still struggling on this, here is some help, based on wild guesses i made given your previous posts: with Ada.Text_IO, Ada.Streams, Ada.Streams.Stream_IO; procedure Main is -- let's assume you have this kind of records type Data_Record is record Some : Integer; Dummy : String (1..8); Fields : Float; end record; -- according to the description you gave in a previous post, -- your message type is implemented (simplified) this way type Data_Record_Array is array (1..512) of Data_Record; type Message is record -- the message header (very simplified) -- holds the number of actual records in the data Number_Of_Records : Natural; -- the message data Data : Data_Record_Array; end record; -- declaration of the custom stream attribute procedures procedure Message_Read( Stream : access Ada.Streams.Root_Stream_Type'Class; Msg : out Message ); for Message'Read use Message_Read; procedure Message_Write( Stream : access Ada.Streams.Root_Stream_Type'Class; Msg : in Message ); for Message'Write use Message_Write; -- implementation of Message'Read procedure Message_Read( Stream : access Ada.Streams.Root_Stream_Type'Class; Msg : out Message ) is Size : Natural; begin -- first read the header -- WARNING: on the network, the size is in bytes, -- not in number of records Natural'Read( Stream, Size ); Msg.Number_Of_Records := Size / (Data_Record'Size / Ada.Streams.Stream_Element'Size); -- then read the data for I in Msg.Data'First..Msg.Data'First + Msg.Number_Of_Records - 1 loop Data_Record'Read( Stream, Msg.Data(I) ); end loop; end Message_Read; -- implementation of Message'Write procedure Message_Write( Stream : access Ada.Streams.Root_Stream_Type'Class; Msg : in Message ) is begin -- first write the header -- WARNING: on the network, the size is in bytes, -- not in number of records Natural'Write( Stream, Msg.Number_Of_Records * Data_Record'Size / Ada.Streams.Stream_Element'Size ); -- then write the data for I in Msg.Data'First..Msg.Data'First + Msg.Number_Of_Records - 1 loop Data_Record'Write( Stream, Msg.Data(I) ); end loop; end Message_Write; -- this is for to simplify test writing use Ada.Streams.Stream_IO; begin -- since socket streams and file streams are identical (really, all streams work the same) -- we will use files for testing -- first write some stuffs to a stream declare F : File_Type; S : Stream_Access; M : Message; begin -- create a new file Create( F, Out_File, "test.out" ); -- get the stream corresponding to the file S := Stream( F ); -- create 5 messages for I in 1..5 loop -- fill each message with dummy data M.Number_Of_Records := I * 2; for J in 1..M.Number_Of_Records loop M.Data(J) := Data_Record'(Some => J, Dummy => "20050509", Fields => 42.0 / Float( I ) + Float( J )); end loop; -- write the data to the stream Message'Write( S, M ); end loop; -- close the file Close( F ); end; -- here you can look at "test.out" and see what it contains. -- now read some stuffs from the stream declare F : File_Type; S : Stream_Access; M : Message; begin -- open the file Open( F, In_File, "test.out" ); -- get the stream corresponding to the file S := Stream( F ); -- read all messages on the stream loop Message'Read( S, M ); -- display the content of the messages Ada.Text_IO.Put_Line( "Message found : " & Natural'Image( M.Number_Of_Records ) & " records =>" ); for I in M.Data'First..M.Data'First + M.Number_Of_Records - 1 loop Ada.Text_IO.Put_Line( " " & Integer'Image( M.Data(I).Some ) & " " & M.Data(I).Dummy & " " & Float'Image( M.Data(I).Fields ) ); end loop; end loop; exception when End_Error => -- when there are no more messages in the stream file, -- close it Close( F ); end; end Main; -- rien ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Sending Variable Length Messages with GNAT.Sockets 2005-05-09 14:51 ` markp 2005-05-09 18:49 ` Adrien Plisson @ 2005-05-09 19:16 ` Simon Wright 2005-05-10 15:08 ` markp 2005-05-10 20:34 ` Simon Wright 1 sibling, 2 replies; 18+ messages in thread From: Simon Wright @ 2005-05-09 19:16 UTC (permalink / raw) "markp" <markwork66@yahoo.com> writes: > I still have a fundamental problem. I am working on legacy code in > which data is defined in records (or arrays of records) which are sent > in variable lengths. We use address, byte count to send the exact > number of bytes. Using Streams, it seems they type has to be of > Stream_element_Array. The only way I can see to send/receive these > "variable" messages is to first read our message header which contains > the number of bytes in the message. Then, create a Stream_Element_Array > of the exact size for the next read. Then, do an unchecked conversion > or a copy bytes routine to get the data into my data type for > processing. Does this sound correct? Sounds pretty good to me; though the compiler is going to complain about the unchecked conversion if your data type isn't the size specified in the header? Assuming you have type my_array_type is array (Natural range <>) of your record type, try something like read the number of bytes; compute the number of array elements; handle the error if it doesn't match exactly; declare Readable : my_array_type (1 .. number_of_array_elements); begin my_array_type'Read (str, Readable); return Readable; -- or something related end; > Lastly, using the 'Read function on streams, am I guaranteed to block > until I receive all bytes? I believe so (unless the other end closes, or you have a non-blocking socket, in which case I'd expect End_Error). ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Sending Variable Length Messages with GNAT.Sockets 2005-05-09 19:16 ` Simon Wright @ 2005-05-10 15:08 ` markp 2005-05-10 20:34 ` Simon Wright 1 sibling, 0 replies; 18+ messages in thread From: markp @ 2005-05-10 15:08 UTC (permalink / raw) Thanks for your reply. As we both expected, it worked fine. ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Sending Variable Length Messages with GNAT.Sockets 2005-05-09 19:16 ` Simon Wright 2005-05-10 15:08 ` markp @ 2005-05-10 20:34 ` Simon Wright 2005-05-11 13:19 ` Marc A. Criley 1 sibling, 1 reply; 18+ messages in thread From: Simon Wright @ 2005-05-10 20:34 UTC (permalink / raw) Simon Wright <simon@pushface.org> writes: > declare > Readable : my_array_type (1 .. number_of_array_elements); > begin > my_array_type'Read (str, Readable); I forgot to say, you need to be careful about the components of records if you're going to let the compiler use the default 'Read/'Write. If the C side says struct rec { char flag; int count; }; there will typically be 3 bytes of padding between flag & count, for 8 bytes on the wire. If the Ada side says type Rec is record Flag : Interfaces.Unsigned_8; Count : Interfaces.Integer_32; end record; pragma Convention (C, Rec); the 'Write will output *5* bytes; but an unchecked conversion to Stream_Element_Array (1 .. 8) will succeed & do The Right Thing (endianness permitting). ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Sending Variable Length Messages with GNAT.Sockets 2005-05-10 20:34 ` Simon Wright @ 2005-05-11 13:19 ` Marc A. Criley 2005-05-11 17:14 ` tmoran 2005-05-11 21:05 ` Simon Wright 0 siblings, 2 replies; 18+ messages in thread From: Marc A. Criley @ 2005-05-11 13:19 UTC (permalink / raw) Simon Wright wrote: > If the C side says > > struct rec { > char flag; > int count; > }; > > there will typically be 3 bytes of padding between flag & count, for 8 > bytes on the wire. > > If the Ada side says > > type Rec is record > Flag : Interfaces.Unsigned_8; > Count : Interfaces.Integer_32; > end record; > pragma Convention (C, Rec); > > the 'Write will output *5* bytes; but an unchecked conversion to > Stream_Element_Array (1 .. 8) will succeed & do The Right Thing > (endianness permitting). This is why trying to use Ada.Streams "out-of-the-box" to communicate between Ada applications and those written in other languages is problematic at best. You pretty much have to write your own stream I/O routines for each type to be transferred to get the data into an interoperable layout, especially for structured types like those in Simon's example. I've pretty much given up on doing that, only using streams for intra-system Ada-to-Ada communication, and doing Unchecked_Conversions to Stream_Element_Array and using GNAT.Sockets for all external comms. Marc A. Criley www.mckae.com ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Sending Variable Length Messages with GNAT.Sockets 2005-05-11 13:19 ` Marc A. Criley @ 2005-05-11 17:14 ` tmoran 2005-05-11 21:05 ` Simon Wright 1 sibling, 0 replies; 18+ messages in thread From: tmoran @ 2005-05-11 17:14 UTC (permalink / raw) > This is why trying to use Ada.Streams "out-of-the-box" to communicate > between Ada applications and those written in other languages is > problematic at best. You pretty much have to write your own stream I/O > routines for each type to be transferred to get the data into an You wouldn't expect to use default Streams to read/write disk files to be exchanged with arbitrary other programs. For just that reason we included a generic capability (like Ada.Sequential_IO's) in Claw.Sockets. Also, a lot of internet stuff is LF-ended text, which needs to be handled more like Text_IO than Streams. It's rather optimistic to expect socket IO to be *simpler* than disk IO. ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Sending Variable Length Messages with GNAT.Sockets 2005-05-11 13:19 ` Marc A. Criley 2005-05-11 17:14 ` tmoran @ 2005-05-11 21:05 ` Simon Wright 2005-05-12 10:24 ` Jacob Sparre Andersen 1 sibling, 1 reply; 18+ messages in thread From: Simon Wright @ 2005-05-11 21:05 UTC (permalink / raw) "Marc A. Criley" <mcNOSPAM@mckae.com> writes: > Simon Wright wrote: > >> If the C side says >> struct rec { >> char flag; >> int count; >> }; >> there will typically be 3 bytes of padding between flag & count, for >> 8 >> bytes on the wire. >> If the Ada side says >> type Rec is record >> Flag : Interfaces.Unsigned_8; >> Count : Interfaces.Integer_32; >> end record; >> pragma Convention (C, Rec); >> the 'Write will output *5* bytes; but an unchecked conversion to >> Stream_Element_Array (1 .. 8) will succeed & do The Right Thing >> (endianness permitting). > > This is why trying to use Ada.Streams "out-of-the-box" to communicate > between Ada applications and those written in other languages is > problematic at best. You pretty much have to write your own stream > I/O routines for each type to be transferred to get the data into an > interoperable layout, especially for structured types like those in > Simon's example. > > I've pretty much given up on doing that, only using streams for > intra-system Ada-to-Ada communication, and doing Unchecked_Conversions > to Stream_Element_Array and using GNAT.Sockets for all external comms. Our project has lots of Ada (our bit) and lots of C (the other bits). The interfaces are defined using only 32-bit quantities (after a packed 20-byte header which initially caused us a pile of grief, especially since we wanted to be interoperable between PC and PowerPC). On our side there's quite a lot of generated code to cope with mapping Booleans to packed arrays of bits, driven by UML tags in the models, but once the data is in the 32-bit form we do indeed use Streams. I suppose we could have achieved the same end by writing our own 'Read, 'Write, but that might have been a bridge too far; and this way at least the main code generator isn't intertwingled with the network i/o part. I can't remember whether that argument occurred to me at the time! ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Sending Variable Length Messages with GNAT.Sockets 2005-05-11 21:05 ` Simon Wright @ 2005-05-12 10:24 ` Jacob Sparre Andersen 2005-05-14 11:12 ` Simon Wright 0 siblings, 1 reply; 18+ messages in thread From: Jacob Sparre Andersen @ 2005-05-12 10:24 UTC (permalink / raw) Simon Wright wrote: > On our side there's quite a lot of generated code to cope with > mapping Booleans to packed arrays of bits, driven by UML tags in the > models, but once the data is in the 32-bit form we do indeed use > Streams. Why not use representation clauses for doing those mappings? (or is the generated code actually mostly generated representation clauses?) Jacob -- "It ain't rocket science!" ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Sending Variable Length Messages with GNAT.Sockets 2005-05-12 10:24 ` Jacob Sparre Andersen @ 2005-05-14 11:12 ` Simon Wright 0 siblings, 0 replies; 18+ messages in thread From: Simon Wright @ 2005-05-14 11:12 UTC (permalink / raw) Jacob Sparre Andersen <sparre@nbi.dk> writes: > Simon Wright wrote: > >> On our side there's quite a lot of generated code to cope with >> mapping Booleans to packed arrays of bits, driven by UML tags in the >> models, but once the data is in the 32-bit form we do indeed use >> Streams. > > Why not use representation clauses for doing those mappings? (or is > the generated code actually mostly generated representation clauses?) Because rep clauses are endian-dependent. I know that there are techniques for writing bit offsets in an endian-independent way, but if humans are involved it's often easier (for both writing and reviewing) to have an Unsigned_32 and do shifts and masks in the good old C way (IME). I have used the in the spec declare un-represented record in the body read raw bytes if big-endian then declare big-endian represented derived record unchecked conversion from raw bytes to represented record begin convert raw bytes to represented record return conversion from represented record to un-represented record end else the same for the little-endian representation technique, but it's a lot of work! ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Sending Variable Length Messages with GNAT.Sockets 2005-05-09 10:39 ` Adrien Plisson 2005-05-09 11:19 ` markp @ 2005-05-09 11:19 ` Jeff C 2005-05-09 11:35 ` markp 2005-05-09 11:57 ` Adrien Plisson 1 sibling, 2 replies; 18+ messages in thread From: Jeff C @ 2005-05-09 11:19 UTC (permalink / raw) Adrien Plisson wrote: > markp wrote: > >> My question is: What if the data type "Msg_Type" was a variable length >> message? Is there a way to send only "x" bytes for Msg_Type, and not >> the entire thing? > > > it depends on your requirements. > > if your receiver is an Ada software, use 'Output instead of 'Write, and > there will be no problems. > > in any case, you can use 'Write, but you will have no way to tell the > size of the message from the stream, unless the message itself contains > its length (a pretty common case). reading variable length messages with > 'Read can become really difficult. > > now choose the way you implement your variable length message. there are > three kind of variable length types: > - variant records with a discriminant > - arrays > - tagged types > each have their pros and their cons... > > also, i can think of no way to send "x" bytes of a type and not the > entire thing, unless writing your own stream input and output procedures. > Note that the last statement is almost written as if this is a bad thing. (And I suspect someone that tried it for the first time might feel that way)...But, there is really nothing wrong with writing your own input and output procedures. It is mildly painful once and then the rest of the code ends up pretty clean. ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Sending Variable Length Messages with GNAT.Sockets 2005-05-09 11:19 ` Jeff C @ 2005-05-09 11:35 ` markp 2005-05-09 11:57 ` Adrien Plisson 1 sibling, 0 replies; 18+ messages in thread From: markp @ 2005-05-09 11:35 UTC (permalink / raw) Ok, You'll have to excuse my ignorance, but I have very little experience with Streams. Could you point me in the right direction? Thanks ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Sending Variable Length Messages with GNAT.Sockets 2005-05-09 11:19 ` Jeff C 2005-05-09 11:35 ` markp @ 2005-05-09 11:57 ` Adrien Plisson 1 sibling, 0 replies; 18+ messages in thread From: Adrien Plisson @ 2005-05-09 11:57 UTC (permalink / raw) Jeff C wrote: >> also, i can think of no way to send "x" bytes of a type and not the >> entire thing, unless writing your own stream input and output procedures. >> > > Note that the last statement is almost written as if this is a bad > thing. (And I suspect someone that tried it for the first time might > feel that way)...But, there is really nothing wrong with writing your > own input and output procedures. It is mildly painful once and then the > rest of the code ends up pretty clean. sorry for not being very friendly in this statement, but it was not my intention to let people feel that way. personnaly i think using well-defined custom stream attributes allows a more language independant use of streams, and as such a better interoperability between softwares. so it is clearly a good thing. -- rien ^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2005-05-14 11:12 UTC | newest] Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2005-05-09 10:11 Sending Variable Length Messages with GNAT.Sockets markp 2005-05-09 10:39 ` Adrien Plisson 2005-05-09 11:19 ` markp 2005-05-09 11:50 ` Adrien Plisson 2005-05-09 14:30 ` John B. Matthews 2005-05-09 14:51 ` markp 2005-05-09 18:49 ` Adrien Plisson 2005-05-09 19:16 ` Simon Wright 2005-05-10 15:08 ` markp 2005-05-10 20:34 ` Simon Wright 2005-05-11 13:19 ` Marc A. Criley 2005-05-11 17:14 ` tmoran 2005-05-11 21:05 ` Simon Wright 2005-05-12 10:24 ` Jacob Sparre Andersen 2005-05-14 11:12 ` Simon Wright 2005-05-09 11:19 ` Jeff C 2005-05-09 11:35 ` markp 2005-05-09 11:57 ` Adrien Plisson
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox