Tags: huzzah

diesel, learning, evil, sweeti

all the cool kids are AJAXing - why can't I?

We have some user images on a server (let's call it 'a') at work and I wanted to automatically inline them on another page on another server (which, for demonstration purposes we shall call 'b') if they exist. This, I felt, was a job for this AJAX malarkey that I'd heard so much about.

This

    <html>                                                                              
    <head>                                                                              
    <script type="text/javascript">                                                     
    function picture(name)                                                              
    {                                                                                   
        var xmlhttp=false;                                                              
    /*@cc_on @*/                                                                        
    /*@if (@_jscript_version >= 5)                                                      
        // JScript gives us Conditional compilation                                     
        // so we can cope with old IE versions.                                         
        // and security blocked creation of the objects.                                
        try {                                                                           
            xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");                              
        } catch (e) {                                                                   
            try {                                                                       
                xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");                       
            } catch (E) {                                                               
                xmlhttp = false;                                                        
            }                                                                           
        }                                                                               
    @end @*/                                                                            
        if (!xmlhttp && typeof XMLHttpRequest!='undefined') {                           
            xmlhttp = new XMLHttpRequest();                                             
        }                                                                               
                                                                                    
        var url     = "http://a/"+name+".jpg";                                
        xmlhttp.open("HEAD", url,true);                                                 
        xmlhttp.onreadystatechange=function() {                                         
            if (xmlhttp.readyState==4) {                                                
                if (xmlhttp.status==200) {                                              
                    document.write("<img src='"+url+"'>");                              
                }                                                                       
            }                                                                           
        }                                                                               
        xmlhttp.send(null);                                                             
    }                                                                                   
    </script>                                                                           
    </head>                                                                             
    <body>                                                                              
                                                                                    
    <div>                                                                               
          <script type="text/javascript">                                                   
            picture('foobar')                                                           
          </script>                                                                         
    </div>                                                                              
                                                                                    
    <div>                                                                               
          <script type="text/javascript">                                                   
              picture('doesnt exist')                                                       
          </script>                                                                         
    </div>                                     
    </body>
    </html>

didn't work, throwing up errors like

    "uncaught exception: Permission denied to call method XMLHTTRequest.open"

To get round the security thing I had to stick a script on b

    #!/usr/bin/perl -w                                                                  
                                                                                    
    use strict;                                                                         
    use CGI;                                                                            
    use LWP::Simple;                                                                    
                                                                                    
    $|++;                                                                               
                                                                                    
    my $q = CGI->new;                                                                   
    my $n = $q->param('url');                                                          
    my $u = "http://a/${n}.jpg";                                              
    if (head($u)) {                                                                     
        print $q->header('text/html');                                              
    } else {                                                                            
        print $q->header('text/html', '404 Not Found');                             
    }                                                                                   
                                                                                    
    print "\n";                                                                         
    exit 0; 

And change the line in the javascript to be

    xmlhttp.open("HEAD", "/proxy_check?url="+url,true); 

And lo! It worked. Huzzah!

diesel, learning, evil, sweeti

Data::ICal

Perl is weird. I mean, I know a lot of people think that it's weird full stop but sometimes it really suffers from the opensource malaise - the glaring holes in functionality that everyone knows about but no-one seems to want to fix -PGP is a particular favourite of mine. SOAP::Lite seems to be another massive bug bear. For ages, until the DateTime suite of modules came along, dates and, err, times were like that. I could go on.

ICalendar used to be like that. There was Reefknot - a sort of attempt to do calendaring stuff in Perl which produced Net::ICal and Text::vFile which sort of read .ics files. But, to be frank, they were all shit.

The mighty Richard Clamp did Text::vFile::asData which parsed a file into a loose data structure but it wasn't until Jesse 'RT' Vincent mentioned to me that he'd been writing Data::ICal which had a proper object model and a handy as_string method that things began looking up. But Data::ICal couldn't parse. Which sort of sucked.

Clearly the only avenue open for a good open source citizen was to weave together Text::vFile::asData and Data::ICal which LO! I did. And sorted out their timezone support. And even added tests because I'm attempting to be angelic in a test-driven kind of way. So now Perl has a sensible, easy to use ICalendar module can which round trip an .ics file. HUZZAH!.

diesel, learning, evil, sweeti

URI::Title::iTMS fixages

URI::Title::iTMS is the plugin for URI::Title that copes with Apple's iTunes Music Store URLs. The problem was that it relied on a function from Net::iTMS that was only present in versions less that 0.1, namely

    my $info = fetch_iTMS_info( $uri )
     or die "iTMS / Not an iTMS url";
    $title   =
        eval { "iTMS / " . join(" / ", map { $_->{name} } @{ $info->Path } ) }
        || "iTMS / Error getting title from $uri: $@";

so upgrading to the latest version would break URI::Title::iTMS. After dicking around for a bit I realised you could get the same info out of the new one by using a slightly more convoluted route,

    my $r    =  Net::iTMS::Request->new( );
    my $info = $r->url($uri);
    my $path = $info->root->first_child('Path');
    $title   = eval { "iTMS / " . join(" / ", map { $_->att('displayName') } 
            $path->children('PathElement') ) }
        || "iTMS / Error getting title from $uri: $@";

So it was easy to do a

    eval { require Net::iTMS::Request };
    if ($@) {
        # first version
        # ...
    } else {
        # second version
        # ...
    }

I also noticed iTMS would do internal redirects with itms:// as the scheme which would, naturally, break LWP so I also added

    $r->{_ua} = MyLWP->new;
    $r->{_ua}->agent('iTunes/4.2 (Macintosh; U; PPC Mac OS X 10.2)');

with MyLWP being ...

    package MyLWP;
    use base qw(LWP::UserAgent);
    sub prepare_request {
        my ($self, $request) = @_;
        my $uri = $request->uri;
        $uri->scheme('http');
        $request->uri($uri);
        return $request;
    }

And it all seemed to work. HUZZAH!