Using jQuery And Mootools On The Same Page

While it’s never a good idea to bloat your webpage with too much unneeded content, there are times when you can’t avoid it. One example I came across recently was with my day job’s adoption of jQuery as our official JavaScript framework, I needed to add some jQuery goodness to some blog pages belonging to a certain category in Movable Type. Simple, right?

Well the site in question already used Mootools extensively, so the jQuery would have to run nicely next Mootools and not disrupt existing functionality.

The designers of jQuery have designed for this sort of situation, and have provided a function called noConflict that returns the use of $ to Mootools, or any other framework you may have installed as well.

Here’s some example code to show both jQuery and Mootools running in the same page…

<script type="text/javascript" src="jquery-1.3.2.min.js"></script>
<script type="text/javascript"><!--
jQuery.noConflict();
//-->
</script>
<script type="text/javascript" src="mootools-1.2-core-yc.js"></script>

In my Movable Type situation, I am able to use a custom MT tag to make sure jQuery only appears for certain categories. Let’s assume I have a category called jQuery where I need the jQuery library to be imported, the MTIfCategory tag is what I need to guard with…

<MTIfCategory label="jQuery">
<script type="text/javascript" src="jquery-1.3.2.min.js"></script>
<script type="text/javascript"><!--
jQuery.noConflict();
//-->
</script>
</MTIfCategory>
<script type="text/javascript" src="mootools-1.2-core-yc.js"></script>

With this in place I can call jQuery functions using the jQuery variable, and MooTools using $ where necessary.

Q Radio Player

Q Radio Player

Q Radio officially relaunched today at 6pm with Samanthi’s QPM show.

I’ve been spending the past few weeks working on the new Q Radio Player.

Really it should have a “beta” somewhere in the title as it’s still being refined based on user feedback, like any other good site.

We have expanded on the old Q Radio Player on Whatson.com.

Improvements include…

  • Now playing information
  • Track artwork and links to buy on Amazon or iTunes
  • Listing previous tracks heard
  • Current show snformation
  • Previous and next show information
  • Listen again for previous shows, along with now playing information
  • Voting on tracks so users can feed back if they like the station output or not
  • Flash streaming, so more users can listen in
  • And more…

Comments (hopefully not bug reports, though they are welcome)? Just contact me.

Atom Posting To Movable Type

For the Q Awards 2007, we wanted to have minute by minute blogging.

q awards minute by minute

We used Movable Type for the website, but didn’t want to have to rely on having a laptop available to blog from, so blogging from a mobile phone was the approach we took.

Originally we looked at Twitter for this, but we worried about connection speed. We also looked at Nokia Lifeblog, while good, it doesn’t really allow for just headline posting. Finally, we took the custom code approach.

Movable Type has an Atom interface, it’s what Nokia Lifeblog uses. This lets us post articles, so all we needed was a suitable client. Thankfully, using Perl, there is XML::Atom::Client.

Ben Hammersley provides an great tutorial on using the Atom API in Movable Type.

My code needed to take a line of text and post automatically to Movable Type in a certain category (called “livefeed”). I built a really simple HTML page that could be used by any internet enabled phone. It had one text box and one submit button. Copy entered here and submitted would appear in the Movable Type blog automatically.

I needed some glue Perl code behind this page to make this happen. It turned out to be really simple, and here’s the core functionality. I won’t bore you with CGI handling or display code, just the Atom meat.

my $api = XML::Atom::Client->new;
$api->username($username);
$api->password($password);
my $dc = XML::Atom::Namespace->new(dc => 'http://purl.org/dc/elements/1.1/');
my $entry = XML::Atom::Entry->new;
$entry->title($title);
$entry->content('');
$entry->set($dc, 'subject', 'livefeed');
my $edituri = $api->createEntry($posturl, $entry);
if ($edituri) {
## posted ok
} else {
## not posted, $api->errstr has the error message;
}

This code assumes you have a few variables in place, those are

  • $username – the poster’s username
  • $password – the poster’s web services password
  • $posturl – the web service’s post url
  • $subject – the copy to post to the blog

Movable Type has two different passwords per user, it is important we use the webservices password and not the users normal Movable Type password.

Now we were posting and creating entries each post, we wanted to show them all on one page. my collegue Ross wrote this block of code to display the posts.

<MTEntries category="livefeed">
<li>
<MTIfNonEmpty tag="EntryTitle">
<p class="time"><$MTEntryDate format="%I:%M %p"$></p>
<p><$MTEntryTitle$></p>
</MTIfNonEmpty>
</li>
</MTEntries>

This turned out to be a nice, fast solution to getting content up quickly on the day.

Uploading Files To A LAMP Server Using .NET

We had to setup and run a webcam for the Q Awards red carpet earlier this week.

The original plan was to have an old Axis ethernet webcam, connected to a wifi network using a Dlink bridge. After a nightmare of not being able to get the Dlink to work, we gave up and went for a USB webcam connected to a laptop approach.

I had to write some software to handle the capture of the image and the upload to the webserver. Because we wanted to do a few custom things on the way we weren’t able to use out of the box software.

I’ll post on how to use a webcam with .NET another time. What I wanted to document was how to upload a file using .NET to a LAMP server.

It turns out to be easier than I thought for .NET, one line of code can achieve this using the My.Computer.Network.UploadFile Method.

For example, to upload test.txt to http://www.robertprice.co.uk/asp_upload.pl we can do the following (in Visual Basic)…

My.Computer.Network.UploadFile("C:test.txt","http://www.robertprice.co.uk/asp_upload.pl")

Now we need some code at the other end to store this upload. As I was building a webcam application, the uploaded file, an image in this case, was always overwritten.

The uploaded .NET file uses an bog standard HTTP upload as described in RFC 1867.

If we use Perl to read this file, we can use the standard CGI.pm module to do most of the hard work for us.

The uploaded file is passed a parameter called file, so we can create a CGI object and get a reference to this using the param method. Once we have this, we can treat it as a filehandle and read the date off it. Then all we have to do is to write it out to a file.

The following code achieves this.

#!/usr/bin/perl -w
use strict;
use CGI.pm;
my $CGI = new CGI;
my $file = $CGI->param('file');
open(FILE, ">/path/to/my/file/test.txt") or die $!;
while(<$file>) {
print FILE $_;
}
close(FILE);
print "Content-type: text/htmlnn";
print "OKn";

Dynamically Setting Domain Names For Webtrends

We use Webtrends at work to track usage of our websites.

We use the on demand version which relies on embedding a JavaScript tag onto the page. Recently, we’ve moved to using 1st party cookies (cookies set by the site) instead of 3rd party cookies (cookies set externally by webtrends). These are set in the JavaScript tag and are hard coded to the site, a real pain if you happen to move domain names as you need to code them up specifically each time. We got caught out recently by using a tag with the wrong domain name set in it, meaning we were unable to track the page impressions. We needed a solution…

As the tag is being set in JavaScript, we can use JavaScript to set the domain dynamically. Not all our sites are served dynamically so using JavaScript should mean it would work for anyone using this tag.

Here’s the offending bit of code…

// Code section for Set the First-Party Cookie domain
var gFpcDom=".kerrang.com";

This works for anything served from a Kerrang.com domain. However, what if we want to use a different domain for some reason?

We’ll JavaScript has a property in the document object called domain, we can use this at runtime to find out the full domain name the page was served from.

However, we don’t need the full domain name, just parent domain. For example, www.kerrang.com should become kerrang.com.

We can fix this by using several approaches, but the easiest is the split, splice, join method.

Firstly we split the domain into it’s components by splitting on the periods.

document.domain.split('.');

This gives us the array (“www”,”kerrang”,”com”).

Secondly we splice this to remove the first element.

document.domain.split('.').splice(1.3);

This is saying to take 3 elements after the 1st element in the array. This should cover us if we want to use something like kerrang.co.uk. So after running this we need to should have an array looking like this, (“kerrang”,”com”).

Finally we join this back together again, making sure a period is between each joined element.

document.domain.split('.').splice(1,3).join('.');

Running this should give us kerrang.com, which is acceptable to use in the Webtrends tag.

So our final code looks like this…

var gFpcDom = document.domain.split('.').splice(1,3).join('.');

Posting To Movable Type 3.3 Using Nokia Lifeblog

We’ve been installing Movable Type as a blogging solution at work for various sites recently.

We’d been using Typepad, the hosted version of Movable Type for a while, but wanted some extra flexibility and functionality.

One problem we came across was the lack of support for Nokia Lifeblog on Movable Type, compared to Typepad.

Thankfully Martin Higham has worked on this in the past, and even used my old notes on the Nokia Lifeblog Posting Protocol.

However, the current version of Movable Type is 3.3, and Martin’s work only extends to 3.2.

I took Martin’s code, which modifies AtomServer.pm and modified it so it works on Movable Type 3.3. You can download my Nokia Lifeblog compatible AtomServer.pm for Movable Type 3.3 here.

Make sure you follow Martin’s instructions for Movable Type 3.2 as the method is exactly the same and the same caveats apply (namely, this could well break other Atom tools that use your blog as it has to disable some WSSE authentication).

I hope you find it useful!

UPDATE: 22nd November 2006

With version 2.0 of Lifeblog and web upload functionality from Nokia phones, the authentication method has changed slightly. A new version of AtomServer.pm that works with Lifeblog 2.0 is now available.

UPDATE: 26th June 2007

Neils Berkers has been in touch to say he’s adapted the script so it now works with Movable Type 3.35, Lifeblogging Fixed.

Framing Pages With JavaScript

Normally, when building a website, we’d not want our content to be in frames.

However, a project at work involved hosting some content externally from the parent site that was framed in the parent site.

That’s fine, nothing to difficult, but this content also provided an RSS feed and those links had to feed back into the parent page, so needed to launch the site framework around itself if it didn’t already exist.

The solution to this was to be have two JavaScript’s, one in the piece of content, and the other in the parent framework. When the content is loaded it needs to check if it’s framed, and if it’s not to load the parent framework which then needs to reload the content.

Here’s the code that goes into the content…

<script language="JavaScript" type="text/javascript">
if (self == top) {
var newurl = "http://www.myparentsite.com/?url=" + encodeURI(window.location.href);
if (document.images) {
top.location.replace(newurl);
} else {
top.location.href = newurl;
}
}
</script>

So what’s going on here? Well firstly we need to check if the content page has been launched in a frameset or not. To do this we check if self is the same as top. self is a JavaScript object that refers to the current page, and top is a JavaScript object that refers to the top of the current page, so this could be the parent page of multiple framesets. If it’s the same we know we’re at the top of the page and not in a frameset, so we need to launch the parent page architecture. To do this we work out what the URL of a parent will be and get JavaScript to tell the browser to goto to that page. If you look at the code here, you’ll see the parent site I’ve called www.myparentsite.com, but this could be anything. I append a parameter called url that is an encoded version of the current page’s URL.

When our parent page loads, it needs to see if it has a URL parameter to load in the content frame correctly. We use the following code on the parent page to achieve this.

<script language="JavaScript" type="text/javascript">
var newurl = decodeURI(location.search.slice(5));
if (newurl) {
// nothing actually :-)
} else {
newurl = "http://www.framedcontent.com/defaultcontent.html";
}
document.write('<iframe src="' + newurl + '" scrolling="no" width="492" height="680" frameborder="0" ></iframe>')
</script>

All we’re doing here is getting a whatever parameter string is passed in and treating it as a URL. If we don’t have a parameter we use a default. We then create a new iframe referring to this URL.

As you can see we make no effort to check the parameter passed in is a valid URL or even if it’s in the url parameter. This is very bad code, but serves to demonstrate the technique. In real life we’d check for the url parameter and that it is valid.

Using SOAP::Lite With Perl

I’ve been trying to access a SOAP service using Perl for a project, so I took a quick look at CPAN to see what was available. The answer seemed to be to use SOAP::Lite.

This module turned out to be a real devil to use, and my problems with it were probably compounded by my lack of SOAP experience.

SOAP (incase you didn’t know) is a method of accessing remote services using XML. In my case, I was trying to access content supplied by a third party ringtone provider using SOAP over HTTP.

Using SOAP::Lite you have to specify a uri and a proxy. What stumped me for a while is that the proxy is the URI of service you wish to access, and uri is the namespace of the service.

So if the provider I was using had their SOAP service available at ws.robstones-services.co.uk/external.asmx, I would use this as the proxy, and in this case I would use ws.robstones-services.co.uk/External as the urinamespace.

Great, I knew the service I needed was called getCallList, and required a Username and Password to be passed to it. In return it would give me a list of valid content types. The SOAPAction header to be added to the call to proxy, letting the remote SOAP service I wanted to use the service http://ws.robstones-services.co.uk/External/getCallList.

My first attempt was the following code…

#!/usr/bin/perl -w
use strict;
use SOAP::Lite 'trace', 'debug';
my $server = SOAP::Lite
->uri('http://ws.robstones-services.co.uk/External')
->proxy('http://ws.robstones-services.co.uk/external.asmx');
my $returned = $server
->getCallList({
'Username' => 'RobsUser',
'Password' => 'RobsPassword'
});
foreach my $type ($returned->valueof('//getCallListResult/string')) {
next unless ($type); ## ignore any undefs
print "$typen";
}

You’ll notice I’m using trace and debug to see the SOAP messages being sent and received. The dialogue from this script was…

> perl -w test.pl
SOAP::Transport::HTTP::Client::send_receive: POST http://ws.robstones-services.co.uk/external.asmx HTTP/1.1
Accept: text/xml
Accept: multipart/*
Content-Length: 615
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://ws.robstones-services.co.uk/External#getCallList"
<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/1999/XMLSchema" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><namesp1:getCallList xmlns:namesp1="http://ws.robstones-services.co.uk/External"><c-gensym3><Username xsi:type="xsd:string">RobsUser</Username><Password xsi:type="xsd:string">RobsPassword</Password></c-gensym3></namesp1:getCallList></SOAP-ENV:Body></SOAP-ENV:Envelope>
SOAP::Transport::HTTP::Client::send_receive: HTTP/1.1 500 (Internal Server Error) Internal Server Error.
Cache-Control: private
Connection: close
Date: Tue, 29 Nov 2005 15:23:38 GMT
Server: Microsoft-IIS/6.0
Content-Length: 508
Content-Type: text/xml; charset=utf-8
Client-Date: Tue, 29 Nov 2005 15:23:09 GMT
Client-Response-Num: 1
X-AspNet-Version: 1.1.4322
X-Powered-By: ASP.NET
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>Server did not recognize the value of HTTP Header SOAPAction: http://ws.robstones-services.co.uk/External#getCallList.</faultstring>
<detail />
</soap:Fault>
</soap:Body>
</soap:Envelope>

The call didn’t work, you’ll see the SOAPAction variable is wrong, it’s http://ws.robstones-services.co.uk/External#getCallList instead of http://ws.robstones-services.co.uk/External/getCallList.

I needed to get SOAP::Lite to use the correct URL. The secret turned out to be to change the use SOAP::Lite line to the following.

use SOAP::Lite on_action => sub {sprintf '%s/%s', @_},
'trace', 'debug';

on_action is a parameter SOAP::Lite uses to separate the URI from the action, here we’re telling it to use /.

This gave me the following SOAP dialogue…

> perl -w test.pl
SOAP::Transport::HTTP::Client::send_receive: POST http://ws.robstones-services.co.uk/external.asmx HTTP/1.1
Accept: text/xml
Accept: multipart/*
Content-Length: 615
Content-Type: text/xml; charset=utf-8
SOAPAction: http://ws.robstones-services.co.uk/External/getCallList
<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/1999/XMLSchema" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><namesp1:getCallList xmlns:namesp1="http://ws.robstones-services.co.uk/External"><c-gensym3><Username xsi:type="xsd:string">RobsUser</Username><Password xsi:type="xsd:string">RobsPassword</Password></c-gensym3></namesp1:getCallList></SOAP-ENV:Body></SOAP-ENV:Envelope>
SOAP::Transport::HTTP::Client::send_receive: HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Connection: close
Date: Tue, 29 Nov 2005 15:22:53 GMT
Server: Microsoft-IIS/6.0
Content-Length: 405
Content-Type: text/xml; charset=utf-8
Client-Date: Tue, 29 Nov 2005 15:22:25 GMT
Client-Response-Num: 1
X-AspNet-Version: 1.1.4322
X-Powered-By: ASP.NET
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><getCallListResponse xmlns="http://ws.robstones-services.co.uk/External"><getCallListResult><string xsi:nil="true" /></getCallListResult></getCallListResponse></soap:Body></soap:Envelope>

Bugger, it still didn’t work. I looked again at the SOAP message being sent. It was sending a lot of namespace information and a wrapper around the Username and Password. The wrapper was definitely wrong, and the remote .NET service didn’t seem to like the namespaces.

I needed to sort that out, so I had to tell SOAP::Lite to not to include namespaces or wrap up the Username and Password. The way to do this is to use SOAP::Data to hardcode the data being sent.

This meant changing the call to getCallList to the following…

my $returned = $server
->getCallList(
SOAP::Data->name('Username')->value('RobsUser')->type(''),
SOAP::Data->name('Password')->value('RobsPassword')->type('')
);

The SOAP dialogue after these changes looked like this..

SOAP::Transport::HTTP::Client::send_receive: POST http://ws.robstones-services.co.uk/external.asmx HTTP/1.1
Accept: text/xml
Accept: multipart/*
Content-Length: 548
Content-Type: text/xml; charset=utf-8
SOAPAction: http://ws.robstones-services.co.uk/External/getCallList
<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/1999/XMLSchema" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><namesp1:getCallList xmlns:namesp1="http://ws.robstones-services.co.uk/External"><Username>RobsUser</Username><Password>RobsPassword</Password></namesp1:getCallList></SOAP-ENV:Body></SOAP-ENV:Envelope>
SOAP::Transport::HTTP::Client::send_receive: HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Connection: close
Date: Tue, 29 Nov 2005 15:19:49 GMT
Server: Microsoft-IIS/6.0
Content-Length: 405
Content-Type: text/xml; charset=utf-8
Client-Date: Tue, 29 Nov 2005 15:19:21 GMT
Client-Response-Num: 1
X-AspNet-Version: 1.1.4322
X-Powered-By: ASP.NET
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><getCallListResponse xmlns="http://ws.robstones-services.co.uk/External"><getCallListResult><string xsi:nil="true" /></getCallListResult></getCallListResponse></soap:Body></soap:Envelope>

Close, but still not right. The problem was with the getCallList itself, it was still trying to use a namespace.

The final solution was to this problem was to not use getCallList, but instead to use SOAP::Lite’s call method to implicitly set how the function was being called.

The code after making this change was the following…

my $returned = $server
->call(SOAP::Data->name('getCallList')->attr({xmlns => 'http://ws.robstones-services.co.uk/External'}) =>
SOAP::Data->name('Username')->value('RobsUser')->type(''),
SOAP::Data->name('Password')->value('RobsPassword')->type('')
);

This gave me the SOAP dialogue…

> perl -w test_soap.pl
SOAP::Transport::HTTP::Client::send_receive: POST http://ws.robstones-services.co.uk/external.asmx HTTP/1.1
Accept: text/xml
Accept: multipart/*
Content-Length: 524
Content-Type: text/xml; charset=utf-8
SOAPAction: http://ws.robstones-services.co.uk/External/getCallList
<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/1999/XMLSchema" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><getCallList xmlns="http://ws.robstones-services.co.uk/External"><Username>RobsUser</Username><Password>RobsPassword</Password></getCallList></SOAP-ENV:Body></SOAP-ENV:Envelope>
SOAP::Transport::HTTP::Client::send_receive: HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Connection: close
Date: Tue, 29 Nov 2005 15:16:07 GMT
Server: Microsoft-IIS/6.0
Content-Length: 540
Content-Type: text/xml; charset=utf-8
Client-Date: Tue, 29 Nov 2005 15:15:39 GMT
Client-Response-Num: 1
X-AspNet-Version: 1.1.4322
X-Powered-By: ASP.NET
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><getCallListResponse xmlns="http://ws.robstones-services.co.uk/External"><getCallListResult><string>ROBS_JAVA</string><string>ROBS_WALL</string><string>ROBS_POLY</string><string>ROBS_MONO</string><string>ROBS_REAL</string><string xsi:nil="true" /></getCallListResult></getCallListResponse></soap:Body></soap:Envelope>
ROBS_JAVA
ROBS_WALL
ROBS_POLY
ROBS_MONO
ROBS_REAL

Hurrah, after all that effort, I have a list of 5 types of content offered by my third party supplier. I can now go ahead and build my service.

SOAP::Lite is a powerful module, but the lack of simple, easy to follow documentation and examples holds it back. I hope this small article helps out other programmers just starting on the SOAP path.

Whatson.com – The Best In UK Commercial Radio

Whatson.com - Kerrang

I’m really pleased as I made the new Whatson.com site live today. It’s the result of several months hard work by a small team, with me as the lead developer.

Currently it’s the home for 8 radio players at present, with more to follow soon!

Kerrang Radio, Kerrang 105.2, Kiss 100 and Magic 105.4 contain a mix of live radio streams, the best of the weeks previous shows and some other special content.

The BBC has been doing something similar for a while with the BBC Radio Player, and ourselves with the Kiss player, but this a first for UK commercial radio.

All the players cross link to each other and we try to offer highlights from other stations to give visitors a real choice of listening.

Anyway, there’s more to come, so keep tuned in.

Whatson.com - Kiss

Whatson.com - Heat

Whatson.com - Smash Hits