From rkleeman at energoncube.net Wed Dec 9 16:25:22 2009 From: rkleeman at energoncube.net (Bob Kleemann) Date: Wed, 9 Dec 2009 16:25:22 -0800 Subject: [San-Diego-pm] A few questions of Perl In-Reply-To: <864c84a00912082300i3dbf5665r20fb6566fe40c120@mail.gmail.com> References: <864c84a00912082300i3dbf5665r20fb6566fe40c120@mail.gmail.com> Message-ID: Alex, I know that you can do what you are looking for, but I haven't done them myself. Therefore I'm forwarding your message to the group to see who has some answers for you. Perl Mongers, Can you help Alex out. Please include his address on replies, as I don't believe he is subscribed to our mailing list yet. (Alex, see our website for information about subscribing to our low-volume list.) On Tue, Dec 8, 2009 at 11:00 PM, Alex (Yu) Hu wrote: > Hi: > > I am sorry to E-mail you like this. My name is Alex Hu. I am living in San > Diego. I am working on a perl program that > is suppose to be a test application running on PC. > > I got your E-mail address by following links from Perl Monger website. I > needed help urgently and I > don't know where to turn to. That's why I am trying your E-mail address. > > If you don't mind, I have two questions regarding Perl: > > 1. The perl program I am running has a network interface which is acting > like a TCP client. For some > reason, I want the client to send message on one port and receive message > on the other port. Is this > possible in perl? I have a module does the send and receive on one port, > but I don't know how to > add a second one. > > 2. Is there a event scheduler modules I can use to schedule the sending of > a message say several milisecond in the future. > > Once again, I am sorry about my E-mail. > > Thanks. > -- > Alex Hu > -------------- next part -------------- An HTML attachment was scrubbed... URL: From christopher.p.hart at gmail.com Wed Dec 9 17:49:10 2009 From: christopher.p.hart at gmail.com (Christopher Hart) Date: Wed, 9 Dec 2009 17:49:10 -0800 Subject: [San-Diego-pm] A few questions of Perl In-Reply-To: References: <864c84a00912082300i3dbf5665r20fb6566fe40c120@mail.gmail.com> Message-ID: 1. I would assume, (possibly incorrectly) that using the Socket or IO::Socket modules would provide the inherent ability to open more than one tcp socket for send/receive. Although i could see being limited in having more than one [socket bound to a] filehandle open, there are always a billion ways to do something in perl. 2. I've seen someone do a sleep(undef, undef, undef, 0.2); to wait a quarter-second, but i can't confirm it works. good luck :) 2009/12/9 Bob Kleemann > Alex, > > I know that you can do what you are looking for, but I haven't done them > myself. Therefore I'm forwarding your message to the group to see who has > some answers for you. > > Perl Mongers > > Can you help Alex out. Please include his address on replies, as I don't > believe he is subscribed to our mailing list yet. (Alex, see our website > for information about subscribing to our low-volume list.) > > On Tue, Dec 8, 2009 at 11:00 PM, Alex (Yu) Hu wrote: > >> Hi: >> >> I am sorry to E-mail you like this. My name is Alex Hu. I am living in San >> Diego. I am working on a perl program that >> is suppose to be a test application running on PC. >> >> I got your E-mail address by following links from Perl Monger website. I >> needed help urgently and I >> don't know where to turn to. That's why I am trying your E-mail address. >> >> If you don't mind, I have two questions regarding Perl: >> >> 1. The perl program I am running has a network interface which is acting >> like a TCP client. For some >> reason, I want the client to send message on one port and receive message >> on the other port. Is this >> possible in perl? I have a module does the send and receive on one port, >> but I don't know how to >> add a second one. >> >> 2. Is there a event scheduler modules I can use to schedule the sending of >> a message say several milisecond in the future. >> >> Once again, I am sorry about my E-mail. >> >> Thanks. >> -- >> Alex Hu >> > > > _______________________________________________ > San-Diego-pm mailing list > San-Diego-pm at pm.org > http://mail.pm.org/mailman/listinfo/san-diego-pm > -- Respectfully, Chris Hart Systems Administrator Extrameasures, LLC. 8910 University Center Lane, Suite 475 San Diego, CA 92122 Office - 858.546.1052 x32 Fax - 858.546.1057 -------------- next part -------------- An HTML attachment was scrubbed... URL: From kst at mib.org Wed Dec 9 18:21:13 2009 From: kst at mib.org (Keith Thompson) Date: Wed, 9 Dec 2009 18:21:13 -0800 Subject: [San-Diego-pm] A few questions of Perl In-Reply-To: References: <864c84a00912082300i3dbf5665r20fb6566fe40c120@mail.gmail.com> Message-ID: <20091210022113.GA19516@nuthaus.mib.org> On Wed, Dec 09, 2009 at 05:49:10PM -0800, Christopher Hart wrote: > 1. I would assume, (possibly incorrectly) that using the Socket or > IO::Socket modules would provide the inherent ability to open more than one > tcp socket for send/receive. Although i could see being limited in having > more than one [socket bound to a] filehandle open, there are always a > billion ways to do something in perl. I lack sufficient expertise to comment on this, but ... > 2. I've seen someone do a sleep(undef, undef, undef, 0.2); to wait a > quarter-second, but i can't confirm it works. It's select(undef, undef, undef, 0.25). "perldoc -f select" for more information (you'll need to scroll past the "select FILEHANDLE" version). But I'm not sure that that's what Alex is looking for. He wrote: 2. Is there a event scheduler modules I can use to schedule the sending of a message say several milisecond in the future. which suggests he wants schedule the event to take place in the future, and continue doing other stuff until it triggers. Time:HiRes::ualarm lets you schedule a SIGALRM signal to be delivered after a specified time. -- Keith Thompson (The_Other_Keith) kst at mib.org Nokia "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister" From christopher.p.hart at gmail.com Wed Dec 9 18:32:52 2009 From: christopher.p.hart at gmail.com (Christopher Hart) Date: Wed, 9 Dec 2009 18:32:52 -0800 Subject: [San-Diego-pm] A few questions of Perl In-Reply-To: <20091210022113.GA19516@nuthaus.mib.org> References: <864c84a00912082300i3dbf5665r20fb6566fe40c120@mail.gmail.com> <20091210022113.GA19516@nuthaus.mib.org> Message-ID: thanks for the save on 2 keith. :) i was off by a mile, and Time::HiRes is a great suggestion for the relative OS independence. I would hope, but can't confirm, alex is using something *nixy, though "a test application running on PC." is somewhat nondescript in that regard. ;) On Wed, Dec 9, 2009 at 6:21 PM, Keith Thompson wrote: > On Wed, Dec 09, 2009 at 05:49:10PM -0800, Christopher Hart wrote: > > 1. I would assume, (possibly incorrectly) that using the Socket or > > IO::Socket modules would provide the inherent ability to open more than > one > > tcp socket for send/receive. Although i could see being limited in having > > more than one [socket bound to a] filehandle open, there are always a > > billion ways to do something in perl. > > I lack sufficient expertise to comment on this, but ... > > > 2. I've seen someone do a sleep(undef, undef, undef, 0.2); to wait a > > quarter-second, but i can't confirm it works. > > It's select(undef, undef, undef, 0.25). "perldoc -f select" for > more information (you'll need to scroll past the "select FILEHANDLE" > version). > > But I'm not sure that that's what Alex is looking for. He wrote: > > 2. Is there a event scheduler modules I can use to schedule the sending > of > a message say several milisecond in the future. > > which suggests he wants schedule the event to take place in the future, > and continue doing other stuff until it triggers. > > Time:HiRes::ualarm lets you schedule a SIGALRM signal to be delivered > after a specified time. > > -- > Keith Thompson (The_Other_Keith) kst at mib.org > > > Nokia > "We must do something. This is something. Therefore, we must do this." > -- Antony Jay and Jonathan Lynn, "Yes Minister" > -- Respectfully, Chris Hart Systems Administrator Extrameasures, LLC. 8910 University Center Lane, Suite 475 San Diego, CA 92122 Office - 858.546.1052 x32 Fax - 858.546.1057 -------------- next part -------------- An HTML attachment was scrubbed... URL: From gautam.dey77 at gmail.com Wed Dec 9 22:14:25 2009 From: gautam.dey77 at gmail.com (Gautam Dey) Date: Wed, 9 Dec 2009 22:14:25 -0800 Subject: [San-Diego-pm] A few questions of Perl In-Reply-To: References: <864c84a00912082300i3dbf5665r20fb6566fe40c120@mail.gmail.com> Message-ID: <9f662fe00912092214o215f72a0w16a93475f1346afb@mail.gmail.com> Alex, There are a few ways to do this. It is definitely doable in perl. The hard way, is to use select and Socket or Socket::IO, with two sockets open on to two different ports. You can then use one as a read socket and another as a write socket.. However, if you do not want to manage the run loop, where you are checking on select in a while(1) look to see if there are any message, you can use POE (http://search.cpan.org/dist/POE/) or something like AnyEvent (http://search.cpan.org/~mlehmann/AnyEvent-5.22/lib/AnyEvent.pm) to help you out. I'd recommend using POE or AnyEvent. POE takes a bit to understand but was created for this very purpose. Gautam. 2009/12/9 Bob Kleemann : > Alex, > > I know that you can do what you are looking for, but I haven't done them > myself.? Therefore I'm forwarding your message to the group to see who has > some answers for you. > > Perl Mongers, > > Can you help Alex out.? Please include his address on replies, as I don't > believe he is subscribed to our mailing list yet.? (Alex, see our website > for information about subscribing to our low-volume list.) > > On Tue, Dec 8, 2009 at 11:00 PM, Alex (Yu) Hu wrote: >> >> Hi: >> >> I am sorry to E-mail you like this. My name is Alex Hu. I am living in San >> Diego. I am? working on a perl program that >> is suppose to be a test application running on PC. >> >> I got your E-mail address by following links from Perl Monger website. I >> needed help urgently and I >> don't know where to turn to. That's why I am trying your E-mail address. >> >> If you don't mind, I have two questions regarding Perl: >> >> 1. The perl program I am running has a network interface which is acting >> like a TCP client. For some >> reason, I want the client to send message on one port and receive message >> on the other port. Is this >> possible in perl?? I have a module does the send and receive on one port, >> but I don't know how to >> add a second one. >> >> 2. Is there a event scheduler modules I can use to schedule the sending of >> a message say several milisecond in the future. >> >> Once again, I am sorry about my E-mail. >> >> Thanks. >> -- >> Alex Hu > > > _______________________________________________ > San-Diego-pm mailing list > San-Diego-pm at pm.org > http://mail.pm.org/mailman/listinfo/san-diego-pm > From tkil at scrye.com Wed Dec 9 22:17:05 2009 From: tkil at scrye.com (Tkil) Date: Wed, 09 Dec 2009 23:17:05 -0700 Subject: [San-Diego-pm] A few questions of Perl In-Reply-To: (Bob Kleemann's message of "Wed, 9 Dec 2009 16:25:22 -0800") References: <864c84a00912082300i3dbf5665r20fb6566fe40c120@mail.gmail.com> Message-ID: >>>>> "Alex" == Alex (Yu) Hu writes: Alex> I am working on a perl program that is suppose to be a test Alex> application running on PC. "on PC" meaning "under windows", yes? Alex> If you don't mind, I have two questions regarding Perl: Alex> 1. The perl program I am running has a network interface which Alex> is acting like a TCP client. For some reason, I want the Alex> client to send message on one port and receive message on the Alex> other port. Is this possible in perl? I have a module does Alex> the send and receive on one port, but I don't know how to add Alex> a second one. It's very much possible: | #!/usr/bin/perl | | use warnings; | use strict; | | use constant BUFFER_SIZE => 1000; | | use IO::Select qw(); | use IO::Socket::INET qw(); | | # set up listening "server" socket: | my $server = IO::Socket::INET->new( LocalPort => 12345, | ReuseAddr => 'true', | Listen => 10 ) | or die "$0: unable to configure server socket"; | | # now set up the output socket: | my $output = IO::Socket::INET->new( PeerAddr => 'localhost:23456' ) | or die "$0: unable to connect to output destination"; | | # add the server socket to the list of things to listen to | my $select = IO::Select->new(); | $select->add( $server ); | | # only need one buffer, so allocate it outside the loop | my $buffer = " " x BUFFER_SIZE; | | # wait for something to happen. | MAIN: | while ( my @ready = $select->can_read() ) | { | foreach my $socket ( @ready ) | { | if ( $socket eq $server ) | { | # new incoming connection | my $new_client = $server->accept(); | $select->add( $new_client ); | } | else | { | # incoming info; read it, then forward to output | $buffer = ""; | recv $socket, $buffer, BUFFER_SIZE, 0; | my $bytes = length $buffer; | if ( $bytes ) | { | send $output, $buffer, $bytes; | } | else | { | # empty read means eof | $select->remove( $socket ); | } | last MAIN if $buffer =~ m!^quit\s*!s; | } | } | } | | exit 0; Alex> 2. Is there a event scheduler modules I can use to schedule the Alex> sending of a message say several milisecond in the future. If you're doing everything synchronously, then the 4-argument "select" solution (as described in previous messages on the list) will work: just wait for the given amount of time, then send the message. If you're doing things asynchronously, then you're suddenly in a much more complex world. Basically, you have to recast your program into event-driven terms; once you've done that, you can either create timer events on a new handle (and use a loop similar to the one above), or you can investigate some of the object/event-oriented Perl libraries (of which POE seems to be an ongoing favorite.) HTH, t. From tkil at scrye.com Thu Dec 10 12:59:48 2009 From: tkil at scrye.com (Tkil) Date: Thu, 10 Dec 2009 13:59:48 -0700 Subject: [San-Diego-pm] A few questions of Perl In-Reply-To: (tkil@scrye.com's message of "Wed, 09 Dec 2009 23:17:05 -0700") References: <864c84a00912082300i3dbf5665r20fb6566fe40c120@mail.gmail.com> Message-ID: (Alex -- it's generally better to keep conversations on the list; that way, you get the benefit of more eyes, and others can find the information later. Thanks!) > >>>>> "Alex" == Alex (Yu) Hu writes: Alex> Thanks Tkil. I am pretty much using a similar way to build my Alex> socket interface. Regarding the two sockets, I want both socket Alex> to be readable and writable. Here is my code, it is working but Alex> sometimes gives me strange behavior: I don't know if it got munged by your mailer, but the indentation was pretty messed up. After cleaning up whitespace, I got: Alex> | $swe_sock = new IO::Socket::INET->new( PeerAddr=>'192.168.0.2', Alex> | PeerPort=>1850, Alex> | Proto=>'tcp', Alex> | Type=>SOCK_STREAM, Alex> | Reuse=>1 ) Alex> | || die "Can't connect to 192.168.0.2:1850 : $!\n"; Alex> | Alex> | $swe_sock->autoflush(1); Alex> | Alex> | $dsp_sock = new IO::Socket::INET->new( PeerAddr=>'192.168.0.2', Alex> | PeerPort=>1852, Alex> | Proto=>'tcp', Alex> | Type=>SOCK_STREAM, Alex> | Reuse=>1 ) Alex> | || die "Can't connect to 192.168.0.2:1852 : $!\n"; Alex> | Alex> | $dsp_sock->autoflush(1); Alex> | Alex> | $sel = IO::Select->new; Alex> | $sel->add($swe_sock); Alex> | $sel->add($dsp_sock); Alex> | Alex> | while ( @ready = $sel->can_read ) Alex> | { Alex> | foreach $fh (@ready) Alex> | { Alex> | Alex> | #read your data Alex> | my $count = sysread($fh, $bytes, 1024); Alex> | Alex> | $string .= $bytes; Alex> | Alex> | if ($fh == $dsp_sock) Alex> | { Alex> | print "Message from DSP_Sock.\n"; Alex> | } Alex> | Alex> | if ($fh == $swe_sock) Alex> | { Alex> | print "Message From SWE_Sock.\n"; Alex> | } Alex> | Alex> | # do something with $line Alex> | #print the results on a third socket Alex> | &msg_proc($string); Alex> | $string=""; Alex> | } Alex> | } A substantial problem is that you're not using "strict" nor "warnings". Those would have told you at least one problem, which is that you can't use "==" on IO::Socket objects... Huh. Turns out you can. That surprises me: | $ perl -Mstrict -MIO::Socket::INET= -lwe \ | 'my $s = IO::Socket::INET->new( PeerAddr => "www.google.com:80" ) or die $!; | print 0+$s;' | 21700712 So much for that theory. Anyway, a few comments: 1. "new Class->new( ... )" is ... odd. It might actually work (and apparently it does, since you're getting something sometimes), but you really only need one of those "new"s. I personally prefer the latter, so you end up with just "Class->new( ... )". 2. Most of the arguments you are giving to the IO::Socket::INET constructor are the defaults, so you can omit them. 3. IO::Socket has had 'autoflush' turned on for years now; if you're in control of your perl install, and if this script is just for limited internal testing, you can probably omit those calls as well. 4. I suspect that you cut out some of the processing, but you don't really need a separate $string variable; you can operate directly on the $bytes in the main loop. Anyway, a cleaned-up version of the code. First, always use 'strict' and 'warnings': | #!/usr/bin/perl | | # paranoia | use strict; | use warnings; Out of habit, I try to avoid bringing anything into my namespace that I don't need. This is probably overkill, but better that you miss something now (and have perl tell you that you need it), than to unexpectedly get a value or function brought in. | # limit imports | use IO::Socket::INET qw(); | use IO::Select qw(); And I like to put all the "magic values" into one place up top: | # constants | my $SWE_ADDR = '192.168.0.2:1850'; | my $DSP_ADDR = '192.168.0.2:1852'; I almost made a subroutine for these two, but I managed to restrain myself. (Did I mention something about how I dislike repetition?) | # set up sockets | my $swe_sock = IO::Socket::INET->new( PeerAddr => $SWE_ADDR, | Reuse => 1 ) | or die "Can't connect to $SWE_ADDR: $!\n"; | | my $dsp_sock = IO::Socket::INET->new( PeerAddr => $DSP_ADDR, | Reuse => 1 ) | or die "Can't connect to $DSP_ADDR: $!\n"; | | # listen to both sockets | my $sel = IO::Select->new(); | $sel->add( $swe_sock ); | $sel->add( $dsp_sock ); | | while ( my @ready = $sel->can_read() ) | { | foreach my $fh ( @ready ) | { | my $bytes; | my $count = sysread( $fh, $bytes, 1024 ); | | if ( $fh == $dsp_sock ) | { | print "Message from DSP_Sock.\n"; | } | elsif ( $fh == $swe_sock ) | { | print "Message From SWE_Sock.\n"; | } | | &msg_proc( $bytes ); | } | } That compiled and ran... but as you said, it didn't do anything. Next we try some debugging prints: | while ( my @ready = $sel->can_read() ) | { | print STDERR "select: " . @ready . " handles ready\n"; | foreach my $fh ( @ready ) | { | my $bytes; | my $count = read( $fh, $bytes, 1024 ); | print STDERR "read: $fh: $count bytes\n"; | | if ( $fh == $dsp_sock ) | { | print STDERR "Message from DSP_Sock.\n"; | } | elsif ( $fh == $swe_sock ) | { | print STDERR "Message From SWE_Sock.\n"; | } | | # &msg_proc( $bytes ); | } | } And running it gave me just this: | $ ./alex-sockets-2.plx | select: 1 handles ready For comparison, adding debugging to the code I posted yesterday evening gives me output something like this: | $ ./alex-sockets.plx | server: IO::Socket::INET=GLOB(0x19ef3f8) | output: IO::Socket::INET=GLOB(0x1939388) | select: IO::Select=ARRAY(0x19ef260) | IO::Select=ARRAY(0x19ef260): 1 sockets ready | new client: IO::Socket::INET=GLOB(0x19ef578) | IO::Select=ARRAY(0x19ef260): 1 sockets ready | IO::Socket::INET=GLOB(0x19ef578): 4 bytes 'bar\n' | IO::Select=ARRAY(0x19ef260): 1 sockets ready | IO::Socket::INET=GLOB(0x19ef578): goodbye | IO::Select=ARRAY(0x19ef260): 1 sockets ready | new client: IO::Socket::INET=GLOB(0x19ef500) | IO::Select=ARRAY(0x19ef260): 1 sockets ready | IO::Socket::INET=GLOB(0x19ef500): 5 bytes 'quit\n' | $ So it looks like it's blocking on the read... Oh, which I screwed up. You had "sysread" in there, and it works fine. (There's even a warning in 'perlfunc' about mixing "select" with "read".) Now the output looks like this: | $ ./alex-sockets-2.plx | select: 1 handles ready | read: IO::Socket::INET=GLOB(0xdb9200): 4 bytes | Message From SWE_Sock. | select: 1 handles ready | read: IO::Socket::INET=GLOB(0xdb9200): 4 bytes | Message From SWE_Sock. | select: 1 handles ready | read: IO::Socket::INET=GLOB(0xdb9200): 4 bytes | Message From SWE_Sock. | select: 1 handles ready | read: IO::Socket::INET=GLOB(0xdb9080): 6 bytes | Message from DSP_Sock. | select: 1 handles ready | read: IO::Socket::INET=GLOB(0xdb9080): 5 bytes | Message from DSP_Sock. I also set it up so that it sends the message to the other socket, and that works fine. (Those of strong constitution might be amused by the development environment I was using to test this: http://scrye.com/~tkil/perl/emacs-nerd.png http://scrye.com/~tkil/perl/emacs-nerd-2.png That's what I get for still doing all my mailing lists and newsgroups on a remote system -- my local emacs is much prettier. :) Anyway, Here's the final code: ------------------------------------------------------------------------ #!/usr/bin/perl # paranoia use strict; use warnings; # limit imports use IO::Socket::INET qw(); use IO::Select qw(); # constants # my $SWE_ADDR = '192.168.0.2:1850'; # my $DSP_ADDR = '192.168.0.2:1852'; my $SWE_ADDR = 'localhost:1850'; my $DSP_ADDR = 'localhost:1852'; # set up sockets my $swe_sock = IO::Socket::INET->new( PeerAddr => $SWE_ADDR, Reuse => 1 ) or die "Can't connect to $SWE_ADDR: $!\n"; my $dsp_sock = IO::Socket::INET->new( PeerAddr => $DSP_ADDR, Reuse => 1 ) or die "Can't connect to $DSP_ADDR: $!\n"; # listen to both sockets my $sel = IO::Select->new(); $sel->add( $swe_sock ); $sel->add( $dsp_sock ); while ( my @ready = $sel->can_read() ) { print STDERR "select: " . @ready . " handles ready\n"; foreach my $fh ( @ready ) { my $bytes; my $count = sysread $fh, $bytes, 1024; print STDERR "read: $fh: $count bytes\n"; if ( $fh == $dsp_sock ) { print STDERR "Message from DSP_Sock.\n"; syswrite $swe_sock, $bytes; } elsif ( $fh == $swe_sock ) { print STDERR "Message From SWE_Sock.\n"; syswrite $dsp_sock, $bytes; } # &msg_proc( $bytes ); } } ------------------------------------------------------------------------ From rkleeman at energoncube.net Thu Dec 10 15:59:18 2009 From: rkleeman at energoncube.net (Bob Kleemann) Date: Thu, 10 Dec 2009 15:59:18 -0800 Subject: [San-Diego-pm] Meeting next week! Message-ID: Perl Mongers, Just a friendly reminder about next week's monthly meeting. We're meeting at the same time (December 17th, 7 PM), and the same place (Anonymizer.com offices by I-805 & Mira Mesa Blvd). As always, stop on by if you can, and if you know you are coming, please give me a heads up. I hope everyone can make it next week. And if not, please enjoy the holidays! -- Bob -------------- next part -------------- An HTML attachment was scrubbed... URL: From rkleeman at energoncube.net Thu Dec 17 11:27:51 2009 From: rkleeman at energoncube.net (Bob Kleemann) Date: Thu, 17 Dec 2009 11:27:51 -0800 Subject: [San-Diego-pm] Meeting next week! In-Reply-To: References: Message-ID: Just a quick reminder Perl Mongers, Our monthly meeting is tonight, 7 PM at the Anonymizer offices near I-805 and Mira Mesa Blvd. Bring your ideas, questions, thoughts, and holiday cheer so we can chat about it all. Also, drop me a quick note if you're likely to make it tonight and haven't already. On Thu, Dec 10, 2009 at 3:59 PM, Bob Kleemann wrote: > Perl Mongers, > > Just a friendly reminder about next week's monthly meeting. We're meeting > at the same time (December 17th, 7 PM), and the same place (Anonymizer.com > offices by I-805 & Mira Mesa Blvd). As always, stop on by if you can, and > if you know you are coming, please give me a heads up. > > I hope everyone can make it next week. And if not, please enjoy the > holidays! > > -- Bob > -------------- next part -------------- An HTML attachment was scrubbed... URL: