[cgiapp] How to download a dynamically generated file
Hi, I'm trying to figure out a good way to download dynamically generated files (mainly PDF files and ZIP files) using CGI-Application. The user directs his browser at a CGI script, rather than a static PDF file or ZIP file, and that script generates the file in question based on various input variables and then downloads it to the client. At the moment, the only way I can see to do this with CGI-Application is to read the whole generated file into a scalar variable, and return (a reference to) that from the run-mode. This is highly undesirable since the files in question could be very large. What I think I want is for CGI-Application to support run-modes returning some kind of valid filehandle (GLOB reference or IO::Handle). CGI::Application-run() would then read (in small chunks at a time) data from the returned filehandle and output it. The attached patch (against version 3.1) is a quick stab at this. It would need polishing up, but basically works OK as a demonstration of what I'm after. The following simple module (together with the obvious CGI script) shows it in action (albeit on a static file, rather than a dynamically generated one): == package MyDownloader; use CGI::Application; our @ISA = qw(CGI::Application); sub setup { my $self = shift; $self-run_modes(['download']); $self-start_mode('download'); } sub download { my $self = shift; my $type = 'image/gif'; my $file = 'C:\\Temp\\downloadee.gif'; $self-header_props(-type = $type); open FH, $file; return \*FH; } 1; == What are your thoughts on this? Or is there a better way to do what I'm trying to achieve here? Cheers, - Steve --- Application.pm.orig 2003-06-02 13:43:18.0 +0100 +++ Application.pm 2003-09-10 09:07:24.0 +0100 @@ -142,8 +142,8 @@ my $body = eval { $autoload_mode ? $self-$rmeth($rm) : $self-$rmeth() }; die Error executing run mode '$rm': $@ if $@; -# Support scalar-ref for body return -my $bodyref = (ref($body) eq 'SCALAR') ? $body : \$body; +# Support scalar- and glob-ref for body return +my $bodyref = (ref($body) eq 'SCALAR' or ref($body) eq 'GLOB') ? $body : \$body; # Call cgiapp_postrun() hook $self-cgiapp_postrun($bodyref); @@ -151,12 +151,46 @@ # Set up HTTP headers my $headers = $self-_send_headers(); - # Build up total output - my $output = $headers . $$bodyref; + my $output = $headers; - # Send output to browser (unless we're in serious debug mode!) - unless ($ENV{CGI_APP_RETURN_ONLY}) { - print $output; + if (ref($bodyref) eq 'GLOB') { + unless (defined fileno $bodyref) { + croak(GLOB ref is not a valid filehandle); + } + + # Send headers to browser (unless we're in serious debug mode!) + unless ($ENV{CGI_APP_RETURN_ONLY}) { + print $output; + } + + binmode $bodyref; + binmode STDOUT; + + # Read data from the filehandle in 2KB chunks in case there is a + # large amount of it (and don't rely on the data being text + # with frequent newline separators) + my $len = 0; + my $buf = ''; + while ($len = read $bodyref, $buf, 2048) { + # Send data to browser (unless we're in serious debug mode!) + unless ($ENV{CGI_APP_RETURN_ONLY}) { + print $buf; + } + } + + # read() returns undef on failure + unless (defined $len) { + croak(Error reading from filehandle: $!); + } + } + else { + # Build up total output + $output .= $$bodyref; + + # Send output to browser (unless we're in serious debug mode!) + unless ($ENV{CGI_APP_RETURN_ONLY}) { + print $output; + } } # clean up operations - Web Archive: http://www.mail-archive.com/[EMAIL PROTECTED]/ http://marc.theaimsgroup.com/?l=cgiappr=1w=2 To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [cgiapp] How to download a dynamically generated file
Steve, I believe the best way would be to redirect the user to a page which has its headers set to the appropriate MIME type. In a simple (non-C::A) CGI, you can use the following line... [ generate your file ] print header(-type = text/comma-separated-values, -attachment = download.csv); Then print the data to the browser. For PDFs and ZIPs, I'm not sure if you can simply print, but let us know if you succeed. Also, there are semi-mature PHP resources which work with generated PDFs. - JC Steve Hay [EMAIL PROTECTED] wrote: Hi, I'm trying to figure out a good way to download dynamically generated files (mainly PDF files and ZIP files) using CGI-Application. The user directs his browser at a CGI script, rather than a static PDF file or ZIP file, and that script generates the file in question based on various input variables and then downloads it to the client. At the moment, the only way I can see to do this with CGI-Application is to read the whole generated file into a scalar variable, and return (a reference to) that from the run-mode. This is highly undesirable since the files in question could be very large. What I think I want is for CGI-Application to support run-modes returning some kind of valid filehandle (GLOB reference or IO::Handle). CGI::Application-run() would then read (in small chunks at a time) data from the returned filehandle and output it. The attached patch (against version 3.1) is a quick stab at this. It would need polishing up, but basically works OK as a demonstration of what I'm after. The following simple module (together with the obvious CGI script) shows it in action (albeit on a static file, rather than a dynamically generated one): == package MyDownloader; use CGI::Application; our @ISA = qw(CGI::Application); sub setup { my $self = shift; $self-run_modes(['download']); $self-start_mode('download'); } sub download { my $self = shift; my $type = 'image/gif'; my $file = 'C:\\Temp\\downloadee.gif'; $self-header_props(-type = $type); open FH, $file; return \*FH; } 1; == What are your thoughts on this? Or is there a better way to do what I'm trying to achieve here? Cheers, - Steve - Web Archive: http://www.mail-archive.com/[EMAIL PROTECTED]/ http://marc.theaimsgroup.com/?l=cgiappr=1w=2 To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [cgiapp] How to download a dynamically generated file
Hi John, John Crowley wrote: Steve, I believe the best way would be to redirect the user to a page which has its headers set to the appropriate MIME type. In a simple (non-C::A) CGI, you can use the following line... Hmm. So I use CGI-Application to generate the file and then send a redirect header. The page that the user is redirected to is then handled by a non-CGI-Application CGI script that downloads that file, yes? I would rather do it in one step rather than two, and all inside CGI-Application, if possible. It seems a shame to have to step outside of CGI-Application to achieve something so simple. [ generate your file ] print header(-type = text/comma-separated-values, -attachment = download.csv); I had a look at the CGI.pm manpage, and it says this about the -attachment argument: The -attachment parameter can be used to turn the page into an attachment. Instead of displaying the page, some browsers will prompt the user to save it to disk. The value of the argument is the suggested name for the saved file. That's not inappropriate behaviour for a ZIP file download, but would be annoying for PDF files which the browser normally handles by passing to the Adobe Reader. So I prefer not to use the -attachment argument in those headers. The browser will still pop up a Save As... dialogue box anyway if it doesn't recognise the MIME type or has no action configured for it. Then print the data to the browser. For PDFs and ZIPs, I'm not sure if you can simply print, but let us know if you succeed. Yes, you can print anything you like to the browser as long as (1) you've set the correct Content-Type in the headers (using the -type argument) and (2) you've set both the filehandle that you're reading the file in from and STDOUT that you're writing the file out to to binary mode if you're on a platform like Windoze that does nasty CRLF translations otherwise. - Steve - Web Archive: http://www.mail-archive.com/[EMAIL PROTECTED]/ http://marc.theaimsgroup.com/?l=cgiappr=1w=2 To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [cgiapp] How to download a dynamically generated file
Adam Gent wrote: Hi, There is no reason why it can not be all done within the C::A. If the run mode generates the file and saves it to disk as a temporary file. The run mode can then output the correct header. What would the correct header there be? Do you mean redirect the client to the temporary file that has been generated? The other thing that I wanted to do was clean up the temporary file that was created after it has been sent to the user. This is achievable if C::A's run() method outputted the file itself (the cleanup code could then go in teardown()), but not if it just sent a redirect header. - Steve - Web Archive: http://www.mail-archive.com/[EMAIL PROTECTED]/ http://marc.theaimsgroup.com/?l=cgiappr=1w=2 To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [cgiapp] How to download a dynamically generated file
Steve Hay [EMAIL PROTECTED] wrote I had a look at the CGI.pm manpage, and it says this about the -attachment argument: The -attachment parameter can be used to turn the page into an attachment. Instead of displaying the page, some browsers will prompt the user to save it to disk. The value of the argument is the suggested name for the saved file. When the browser gets a pdf it will open it using Adobe (if the user has set it up that way) and if it doesn't, then the user will be prompted to either download it or open it (using Adobe). So, either way, using CGI and the '-attachment' argument will work. Michael Peters Venzia - Web Archive: http://www.mail-archive.com/[EMAIL PROTECTED]/ http://marc.theaimsgroup.com/?l=cgiappr=1w=2 To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [cgiapp] How to download a dynamically generated file
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 Howdy, We just started doing something similar to what you're looking to do. We're using PDF::Reuse to generate our PDF files, are using CGI::Application, and it's running under mod_perl. On Wed, 10 Sep 2003, Steve Hay wrote: Hmm. So I use CGI-Application to generate the file and then send a redirect header. The page that the user is redirected to is then handled by a non-CGI-Application CGI script that downloads that file, yes? I would rather do it in one step rather than two, and all inside CGI-Application, if possible. We considered this too. Like you said, it seems a like a few too many steps, though it would work in a pinch. It seems a shame to have to step outside of CGI-Application to achieve something so simple. Right. I don't think you have to, you can get CGI::App to do what you need here. So I prefer not to use the -attachment argument in those headers. The browser will still pop up a Save As... dialogue box anyway if it doesn't recognise the MIME type or has no action configured for it. I think you're looking for the 'Content-disposition' header here. By setting it to inline, it suggests to the browser to view it inline, instead of prompting to save it. Then print the data to the browser. For PDFs and ZIPs, I'm not sure if you can simply print, but let us know if you succeed. Yes, you can print anything you like to the browser as long as (1) you've set the correct Content-Type in the headers (using the -type argument) and (2) you've set both the filehandle that you're reading the file in from and STDOUT that you're writing the file out to to binary mode if you're on a platform like Windoze that does nasty CRLF translations otherwise. Agreed, printing does work, which is how we're doing it. There was recently some discussion on Perlmonks about this exact topic (PDF's and CGI::Application): http://perlmonks.org/index.pl?node_id=288443 Now, what's not discussed it what you mentioned about not wanting to read the entire file in. That's an honorable goal :-) We actually aren't doing that... it was just simpler to read the whole file in, send it to the browser, and just use 'exit' afterwards to kill off that Apache child. Our files also aren't particularly big (1MB max, usually much less). This isn't particularly well documented because it's not recommended for typical use -- however, there is a way to tell CGI::Application that you've already sent data to the browser. CGI::Application uses the following code to send data to the browser: # Send output to browser (unless we're in serious debug mode!) unless ($ENV{CGI_APP_RETURN_ONLY}) { print $output; } Which means that if you set the $ENV{CGI_APP_RETURN_ONLY} variable, you can send headers and data to the browser within your run_mode, and cgi::app won't send data to the browser. That would allow you to send your PDF any way you like, including reading it in line by line instead of slurping the whole file in. The problem with the above CGI::App behaviour not being documented is that it can dissapear. I really feel that there are cases where it's necessary to send stuff to the browser from within the run_mode, and I feel yours is a valid one. I hope Jesse will leave the functionality in there, or perhaps even make it easier by making an accessor method for it :-) -Eric - -- Eric Andreychek | Lucy: What happens if you practice the Eric Conspiracy Secret Labs | piano for 20 years and then end up not [EMAIL PROTECTED] | being rich and famous? http://openthought.net | Schroeder: The joy is in the playing. -BEGIN PGP SIGNATURE- Version: GnuPG v1.0.7 (GNU/Linux) iD8DBQE/Xy4IR5UKaDAjAG4RArq2AJ9F4XQFNuPSdwwHvKNt6tmTKdstnACaAzAZ R5CzZ4Un7SV+PZg2sCY0UlQ= =Fn5S -END PGP SIGNATURE- - Web Archive: http://www.mail-archive.com/[EMAIL PROTECTED]/ http://marc.theaimsgroup.com/?l=cgiappr=1w=2 To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [cgiapp] How to download a dynamically generated file
I think you're looking for the 'Content-disposition' header here. By setting it to inline, it suggests to the browser to view it inline, instead of prompting to save it. I've had success using the following header: Content-Type: application/octetstream\n Content-Disposition: attachment; filename=$filename\n\n The problem with the above CGI::App behaviour not being documented is that it can dissapear. I really feel that there are cases where it's necessary to send stuff to the browser from within the run_mode, and I feel yours is a valid one. I hope Jesse will leave the functionality in there, or perhaps even make it easier by making an accessor method for it :-) You should be able to use the argument of 'none' to the CGIApp header_type() method. e.g. $self-header_type('none'); This functionality was added to CGIApp v3.1 on June 2nd. Something along the lines of the following should do the trick: --- my $filename= 'the_pdf_file.pdf; my $output = get_pdf_contents(); my $header= Content-Type: application/octetstream\n; $header .= Content-Disposition: attachment; filename=$filename\n\n; $self-header_type('none'); return $header.$output; --- - Web Archive: http://www.mail-archive.com/[EMAIL PROTECTED]/ http://marc.theaimsgroup.com/?l=cgiappr=1w=2 To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [cgiapp] How to download a dynamically generated file
Steve Hay [EMAIL PROTECTED] wrote: I would rather do it in one step rather than two, and all inside CGI-Application, if possible. It seems a shame to have to step outside of CGI-Application to achieve something so simple. ... The -attachment parameter [...] would be annoying for PDF files which the browser normally handles by passing to the Adobe Reader. So I prefer not to use the -attachment argument in those headers. The browser will still pop up a Save As... dialogue box anyway if it doesn't recognise the MIME type or has no action configured for it. ...you can print anything you like to the browser as long as (1) you've set the correct Content-Type in the headers (using the -type argument) right. i've used that technique to return excel spreadsheets because i didn't want to save temp files on the server, just feed them directly to the browser. in my case i found that returing a scalar (even a multi-megabyte scalar!) worked perfectly fine for my application. it does seem a bit extreme, but this is not the type of thing one generally needs to do for thousands of concurrent users, hundreds of times per second :-) in low volume situations (password protected admin interfaces, etc.) it Just Works. i've done it in cgi mode and mod_perl mode. is this as elegant as it could be? i agree that it isn't. and often i've wished C:A would let me return a callback coderef instead of a scalar, that C:A would just execute repeatedly, until it, say, returned undef. perhaps jesse will consider such a patch... it certainly seems reasonable to want C:A to accept a file handle as a return value. in fact i believe it was relatively recently that he added scalal refs as allowable return values, in reponse to a few requests here on this list... -dave, putting in my vote for callback support too :-) - Web Archive: http://www.mail-archive.com/[EMAIL PROTECTED]/ http://marc.theaimsgroup.com/?l=cgiappr=1w=2 To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [cgiapp] How to download a dynamically generated file
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 Howdy, On Wed, 10 Sep 2003, Steve Comrie wrote: I think you're looking for the 'Content-disposition' header here. By setting it to inline, it suggests to the browser to view it inline, instead of prompting to save it. I've had success using the following header: Content-Type: application/octetstream\n Content-Disposition: attachment; filename=$filename\n\n Great! You should be able to use the argument of 'none' to the CGIApp header_type() method. --- my $filename= 'the_pdf_file.pdf; my $output = get_pdf_contents(); my $header= Content-Type: application/octetstream\n; $header .= Content-Disposition: attachment; filename=$filename\n\n; $self-header_type('none'); return $header.$output; Agreed, but that only surpresses the headers. You still have to read in the entire PDF at once, and then pass it around as a reference. You had asked for a way to send the PDF a few pieces at a time to avoid having the entire file in memory at once. Setting '$ENV{CGI_APP_RETURN_ONLY}', in combination with passing 'none' into header_type(), does exactly that :-) I was just saying that I hope that there might some day be a less cryptic way of going about that. Perhaps it would work today by returning a hash from the run_mode, instead of a string. Then, we could have an overloaded stringify operation call a custom output procedure when CGI::App calls print $output at the end of the run() method. That output procedure would then read a file in, line by line, and avoid the overhead of slurping it in during the run_mode. However, some might suggest that doesn't really make it any less cryptic ;-) -Eric - -- Eric Andreychek | Lucy: What happens if you practice the Eric Conspiracy Secret Labs | piano for 20 years and then end up not [EMAIL PROTECTED] | being rich and famous? http://openthought.net | Schroeder: The joy is in the playing. -BEGIN PGP SIGNATURE- Version: GnuPG v1.0.7 (GNU/Linux) iD8DBQE/XzX8R5UKaDAjAG4RAkRIAKDprvscM4P1mVWJ1JSvjSaLcSRs0wCgmabj coqm0YqNwynpmf2HvfMI1UU= =6cWs -END PGP SIGNATURE- - Web Archive: http://www.mail-archive.com/[EMAIL PROTECTED]/ http://marc.theaimsgroup.com/?l=cgiappr=1w=2 To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [cgiapp] How to download a dynamically generated file
Eric Andreychek wrote: On Wed, 10 Sep 2003, Steve Comrie wrote: You should be able to use the argument of 'none' to the CGIApp header_type() method. --- my $filename= 'the_pdf_file.pdf; my $output = get_pdf_contents(); my $header= Content-Type: application/octetstream\n; $header .= Content-Disposition: attachment; filename=$filename\n\n; $self-header_type('none'); return $header.$output; Agreed, but that only surpresses the headers. You still have to read in the entire PDF at once, and then pass it around as a reference. I think what Steve C was suggesting (correct me if I'm wrong) was for the run-mode to output the headers and the PDF file itself (which it can do in small chunks at a time, instead of all in one go like the example above does), and then set the header type to none and return a null string. Then, C::A's run() method has been instructed to not output headers, and has no content body to output either -- the run-mode has already done it all! This is the answer I've been looking for. Thanks, guys! - Steve - Web Archive: http://www.mail-archive.com/[EMAIL PROTECTED]/ http://marc.theaimsgroup.com/?l=cgiappr=1w=2 To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
[cgiapp] Re: How to download a dynamically generated file
In article [EMAIL PROTECTED], Steve Hay wrote: --000705070203000702050302 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Hi, I'm trying to figure out a good way to download dynamically generated files (mainly PDF files and ZIP files) using CGI-Application. I've done this before. Here's how I did it: print $self-query-header( -type='application/vnd.ms-excel', -attachment= file.xls, ); # print file to stdout here... exit; ## Sure, I've broken a couple of C::A rules by printing and exiting in the run mode, but I think the code is clearer and easier to maintain than trying follow the C::A structure to the letter and have a result is more complicated to implement and understand. Mark -- . . . . . . . . . . . . . . . . . . . . . . . . . . . Mark StosbergPrincipal Developer [EMAIL PROTECTED] Summersault, LLC 765-939-9301 ext 202 database driven websites . . . . . http://www.summersault.com/ . . . . . . . . - Web Archive: http://www.mail-archive.com/[EMAIL PROTECTED]/ http://marc.theaimsgroup.com/?l=cgiappr=1w=2 To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [cgiapp] How to download a dynamically generated file
You had asked for a way to send the PDF a few pieces at a time to avoid having the entire file in memory at once. Setting '$ENV{CGI_APP_RETURN_ONLY}', in combination with passing 'none' into header_type(), does exactly that :-) Eric, I think you're confusing me with Steve Hay, who originally asked the question ;) I was just saying that I hope that there might some day be a less cryptic way of going about that. Perhaps it would work today by returning a hash from the run_mode, instead of a string. Then, we could have an overloaded stringify operation call a custom output procedure when CGI::App calls print $output at the end of the run() method. That output procedure would then read a file in, line by line, and avoid the overhead of slurping it in during the run_mode. However, some might suggest that doesn't really make it any less cryptic ;-) Setting $self-header_type('none'); followed by printing the headers yourself and then opening a file in the run-mode and printing it line by line and finally followed by return ''; *should* hypothetically solve the problem without relying on undocumented CGIApp features. Basically if you return the headers yourself in the run-mode and set the header type to 'none' then when you return nothing to CGIApp it will append nothing to what you've already printed out. A fairly un-elegant solution but then again it's a fairly irregular scenario. I'd imagine that if it's something an application will be doing regularly, a function in the superclass like: sub return_file_contents { my $self = shift; my $file = shift; my $name = shift; # tell CGIApp not to set headers of it's own $self-header_type('none'); # print our own headers print Content-Type: application/octetstream\n; print Content-Disposition: attachment; filename=$name\n\n; # or whatever other method of read / return line by line that may be faster open FILE, $file; print $_ while( FILE ); close FILE; # delete the file unlink ( $file ); # return nothing to CGIApp return ''; } and could then be called at the bottom of the run-mode returning the file as: return $self-return_file_contents( '/usr/home/files/information.pdf', 'Product Information.pdf' ); It's *a* solution, maybe not the best one, but technically one that 'should' work .. ;) - Web Archive: http://www.mail-archive.com/[EMAIL PROTECTED]/ http://marc.theaimsgroup.com/?l=cgiappr=1w=2 To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [cgiapp] How to download a dynamically generated file
Steve Comrie wrote: Setting $self-header_type('none'); followed by printing the headers yourself and then opening a file in the run-mode and printing it line by line and finally followed by return ''; *should* hypothetically solve the problem without relying on undocumented CGIApp features. Exactly. Yes, it does solve the problem - I've just tried it. Thanks! A fairly un-elegant solution but then again it's a fairly irregular scenario. I'd imagine that if it's something an application will be doing regularly, a function in the superclass like: sub return_file_contents [snip] and could then be called at the bottom of the run-mode returning the file as: return $self-return_file_contents( '/usr/home/files/information.pdf', 'Product Information.pdf' ); Not a bad idea. I'll give that a go too. Cheers, - Steve - Web Archive: http://www.mail-archive.com/[EMAIL PROTECTED]/ http://marc.theaimsgroup.com/?l=cgiappr=1w=2 To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [cgiapp] How to download a dynamically generated file
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 Howdy, On Wed, 10 Sep 2003, Steve Comrie wrote: You had asked for a way to send the PDF a few pieces at a time to avoid having the entire file in memory at once. Setting '$ENV{CGI_APP_RETURN_ONLY}', in combination with passing 'none' into header_type(), does exactly that :-) Eric, I think you're confusing me with Steve Hay, who originally asked the question ;) Gak! You're right, I am. My appologies to both of you :-) Setting $self-header_type('none'); followed by printing the headers yourself and then opening a file in the run-mode and printing it line by line and finally followed by return ''; *should* hypothetically solve the problem without relying on undocumented CGIApp features. You're also right here. That didn't click when I first looked at your code. My bad :-) This definitely solves the problem at hand, and is much better off than using the $ENV option. Thanks for your thoughts! -Eric - -- Eric Andreychek | Lucy: What happens if you practice the Eric Conspiracy Secret Labs | piano for 20 years and then end up not [EMAIL PROTECTED] | being rich and famous? http://openthought.net | Schroeder: The joy is in the playing. -BEGIN PGP SIGNATURE- Version: GnuPG v1.0.7 (GNU/Linux) iD8DBQE/Xz4xR5UKaDAjAG4RAu3NAJ9/G4lfK0KEzJ94R1xs2IwEhQ7CQwCg1roY lDJWZp5MiGnYECBSiUepp2E= =oBlS -END PGP SIGNATURE- - Web Archive: http://www.mail-archive.com/[EMAIL PROTECTED]/ http://marc.theaimsgroup.com/?l=cgiappr=1w=2 To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]