Zymic

Webmaster resources

Follow us on Twitter!

Hosting status updates - Click here

PHP & MySQL

Free Tutorials » PHP & MySQL » Create a Visitor Map

This tutorial aims to outline the process of creating a visitor map you sometimes see on MySpace profiles.

Step 1

This tutorial aims to outline the process of creating a visitor map you sometimes see on MySpace profiles. It does not aim to be a definitive guide on creating an incredibly precise map, but rather shows an example of the process involved and how different APIs and data can work together. Due to the nature of the external services used, it is not going to be entirely accurate, however it generally bodes quite well and is accurate to country almost all the time. Eventually, this is the kind of output we'll get:

Step 1 diagram

We will be using three external services: hostip.info, maps.yahoo.com and maps.google.com. The visitor's IP address is gathered, and this is then fed to the hostip.info API. If its location can be determined, then it is passed to the Yahoo Maps API to gather its geographic coordinates. Note: I am aware that the Yahoo API can be bypassed as the hostip.info API provides geographic coordinates, but at the time of writing no such feature was available. However, by the end of the tutorial you should have learned enough to add this functionality in yourself. These will then be plotted using the Google Maps API to create the actual map display. If the location can not be determined, the user is not plotted on the map, so it heavily depends on the APIs involved. A pseudo-flowchart may look something as follows:

Step 1 diagram

What it is advised you should know before using this tutorial:

1) At least a basic understanding of PHP, especially functions and data types (array, boolean etc.)

2) An understanding of databases, namely MySQL and its integration with PHP scripts

3) Hopefully knowledge of what the Document Object Model and XML are, though these are not a necessity

Step 2

The first thing to do is sign up for a Google Maps API key. You can do this here; be sure to read the restrictions and the terms of use.

Step 3

Create a database, naming it something like 'visitormap', and assign it a user. We will have five fields; id, ip, location, longitude and latitude; all hopefully self-explanatory. So, execute the following SQL:

CREATE TABLE `visitor_map` (
 `id` INTEGER auto_increment,
 `ip` VARCHAR(15) NOT NULL,
 `location` VARCHAR(32) NOT NULL,
 `longitude` FLOAT NOT NULL,
 `latitude` FLOAT NOT NULL,
 PRIMARY KEY (`id`)
);

For ease of use, we'll now create a configuration file. Create a file called config.php and insert the following, changing the constant values to suit your database setup and Google Maps API key.

<?php
 
define('DB_HOST', 'localhost');  // Database host
define('DB_NAME', 'visitormap'); // Database being used
define('DB_USER', 'david2012');  // Database user
define('DB_PASS', 'password56'); // Database user's password
 
/* Your Google Maps API key */
define('API_KEY', 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
 
?>

Step 4

We want to create a function in which we can house the code to give us the coordinates and other information we need to create the map display. If you are not very strong on functions, view the Zymic tutorial on functions or visit the PHP manual page. Create a file named visitormap.php with the following (explained afterwards):

<?php
 
function IPtoCoords($ip)
{
	$dom = new DOMDocument();
 
	$ipcheck = ip2long($ip);
    if($ipcheck == -1 || $ipcheck === false)
    	trigger_error('Invalid IP, what are you doing? :|', E_USER_ERROR);
	else
		$uri = 'http://api.hostip.info/?ip=' . $ip;
 
	$dom->load($uri);
	$location = (strpos($dom->getElementsByTagName('name')->item(1)->nodeValue, 'Unknown') === false)
					? $dom->getElementsByTagName('name')->item(1)->nodeValue
					: $dom->getElementsByTagName('countryAbbrev')->item(0)->nodeValue;
 
	if($location == 'XX')
		return false;
	else
	{
		$dom->load('http://local.yahooapis.com/MapsService/V1/geocode?appid=YahooDemo&location=' . $location);
		$longitude = $dom->getElementsByTagName('Longitude')->item(0)->nodeValue;
		$latitude  = $dom->getElementsByTagName('Latitude')->item(0)->nodeValue;
		return array('location' => $location, 'longitude' => $longitude, 'latitude' => $latitude);
	}
}
 
?>

Step 5

<?php
 
function IPtoCoords($ip)
{
	$dom = new DOMDocument();
}
 
?>

Here we create a function called 'IPtoCoords'. Eventually, it will return us an array of the following values: location (be it city or country--however accurate the hostip.info API is), longitude and latitude. Inside the function, PHP's DOMDocument object is instantiated (an instance created of; in this case assigned to the $dom variable) using the 'new' keyword, and this will provide us with methods to grab data from XML outputted from both the hostip.info and Yahoo Maps APIs.

Step 6

<?php
 
function IPtoCoords($ip)
{
	/*$dom = new DOMDocument();*/
 
	$ipcheck = ip2long($ip);
    if($ipcheck == -1 || $ipcheck === false)
    	trigger_error('Invalid IP, what are you doing? :|', E_USER_ERROR);
	else
		$uri = 'http://api.hostip.info/?ip=' . $ip;
 
}
 
?>

We want to make sure the IP is valid, just in case the user is trying something a bit funny. So, we use the PHP function ip2long to check this - it works by converting the IP to a proper address, and then if this either returns -1 or a boolean value of false, we can assume that the given address is invalid. If the IP is invalid, we trigger an error message, however if the IP is indeed correct, we form a URI out of the IP in format http://api.hostip.info/?ip=IP and assign it to a variable for later use - this is the first step in using hostip.info's API.

Step 7

<?php
 
function IPtoCoords($ip)
{
	/*$dom = new DOMDocument();
 
	$ipcheck = ip2long($ip);
    if($ipcheck == -1 || $ipcheck === false)
    	trigger_error('Invalid IP, what are you doing? :|', E_USER_ERROR);
	else
		$uri = 'http://api.hostip.info/?ip=' . $ip;*/
 
	$dom->load($uri);
	$location = (strpos($dom->getElementsByTagName('name')->item(1)->nodeValue, 'Unknown') === false)
					? $dom->getElementsByTagName('name')->item(1)->nodeValue
					: $dom->getElementsByTagName('countryAbbrev')->item(0)->nodeValue;
}
 
?>

First we call the DOMDocument's 'load' method, which loads an external XML file. In this case, it's the $uri variable we created in the previous step. The next section is a bit more complex and uses a ternary operator (short-hand if/else block) Basically, we have the $location variable at the beginning, and will assign it values based on the if/else block. We use the strpos function to test if the second 'name' tag in the XML file contains the word 'Unknown' as returned by the API, using the DOM's getElementsByTagName method. If it does, we use the ISO 3166 country code returned in the 'countryAbbrev' tag, but if not, we use the second 'name' tag as it contains a known location.

Step 8

<?php
 
function IPtoCoords($ip)
{
	/*$dom = new DOMDocument();
 
	$ipcheck = ip2long($ip);
    if($ipcheck == -1 || $ipcheck === false)
    	trigger_error('Invalid IP, what are you doing? :|', E_USER_ERROR);
	else
		$uri = 'http://api.hostip.info/?ip=' . $ip;
 
	$dom->load($uri);
	$location = (strpos($dom->getElementsByTagName('name')->item(1)->nodeValue, 'Unknown') === false)
					? $dom->getElementsByTagName('name')->item(1)->nodeValue
					: $dom->getElementsByTagName('countryAbbrev')->item(0)->nodeValue;*/
 
	if($location == 'XX')
		return false;
	else
	{
		$dom->load('http://local.yahooapis.com/MapsService/V1/geocode?appid=YahooDemo&location=' . $location);
		$longitude = $dom->getElementsByTagName('Longitude')->item(0)->nodeValue;
		$latitude  = $dom->getElementsByTagName('Latitude')->item(0)->nodeValue;
		return array('location' => $location, 'longitude' => $longitude, 'latitude' => $latitude);
	}
}
 
?>

The first two lines are performing a check on the location. If our $location variable was given the contents of the 'countryAbbrev' tag, it may have resolved to 'XX' as provided by the hostip.info API - meaning the country could not be determined. If this is the case, we return a boolean value of false. If not, we begin utilising the Yahoo Maps API, using a similar convention to the hostip.info one.

Again, we load a URI into the DOMDocument's 'load' method, this time loading a Yahoo URI with a 'location' GET value of what is held by our $location variable. The API is clever and the GET value can be a wide range of things, including street, city, state, zip, country (including ISO 3166 code) and various combinations. In our case it will generally either be a city, or if this could not be resolved by the hostip.info API then a country code. With this new URI loaded, we again use the getElementsByTagName method to grab the contents of the first 'Longitude' and 'Latitude' tags with the nodeValue property (which grabs the text content contained within the tag.)

Finally, we set the return values of the function. It is an associative array in the format location: city or country, longitude: location longitude, latitude: location latitude. This will then be used for entering into our database and eventually displaying on a map.

Step 9

Now that we can successfully gain the visitor's location, we can use this to build our finished visitor map. Create a new file (for instance viewmap.php). At the top of your file, put the following:

<?php
 
// Include the configuration and function files we created
require 'config.php';
require 'visitormap.php';
 
// Establish a MySQL connection and select our database using values contained in config.php.
mysql_connect(DB_HOST, DB_USER, DB_PASS);
mysql_select_db(DB_NAME);
 
// Assign the user's IP to a variable and plot it into our function, whose return value is assigned to $userinfo
// Remember, the user's IP is not to be trusted 100%
$ip = $_SERVER['REMOTE_ADDR'];
$userinfo = IPtoCoords($ip);
 
// We select the location column from the database
$user = mysql_query('SELECT `location` FROM `visitor_map` WHERE `location` = \'' . $userinfo['location'] . '\'');
// If it does NOT return a value, and the user's IP could indeed be matched...
// (This makes sure that we have no duplicate rows (which would be a waste) and can determine the visitor's location, respectively)
// ...We insert the values returned by our function into the database, escaping any possible dangerous input
if(!mysql_fetch_row($user) && $userinfo)
	mysql_query('INSERT INTO `visitor_map` (`ip`, `location`, `longitude`, `latitude`) VALUES (\'' . mysql_real_escape_string($ip) . '\', \'' . $userinfo['location'] . '\', ' . $userinfo['longitude'] . ', ' . $userinfo['latitude'] . ')') or die(mysql_error());
 
?>

This is quite simple so explanation is contained within the file itself.

Step 10

Now that we've inserted the user's data into our database, we select all of this information and plot it on a Google Maps object. In the file you just created, you can now create the HTML of the page, including whatever content you wish. The Google Maps API requires the following, however:

1) Include the JavaScript file required for Google Maps, using your API key. Insert the following into the <head> of your HTML page:

<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=<?php echo API_KEY; ?>" type="text/javascript"></script>

2) Certain functions must be triggered on page load and unload. You can use JavaScript event handlers if you want to separate structure from behaviour, but the easiest method is to put the information into the <body> tag:

<body onload="load();" onunload="GUnload();">

Step 11

Now we'll be using the actual Google Maps API to plot the data, which is done using JavaScript. In the head of your HTML document, put the following:

<script type="text/javascript">
//<![CDATA[
 
function load()
{
	if(GBrowserIsCompatible())
	{
		var map = new GMap2(document.getElementById('map'));
		map.addControl(new GLargeMapControl());
		map.setCenter(new GLatLng(0, 0), 1);
 
		<?php
 
		$query = mysql_query('SELECT `longitude`, `latitude` FROM `visitor_map`');
		while($row = mysql_fetch_array($query))
		{
		?>
			map.addOverlay(new GMarker(new GLatLng(<?php echo $row['latitude']; ?>, <?php echo $row['longitude']; ?>)));
 
		<?php
		}
 
		?>
	}
}
 
//]]>
</script>

We start off defining a 'load' function, which is triggered on page load, shown in the previous step. Then, an if statement is used to see if the user's browser supports Google Maps. The next line assigns the map canvas to an HTML element, in this case with an ID of 'map', using the DOM's getElementById method. The following two lines add a large zoom/pan control to the map object and set the default centre of the map when loading to 0 (the centre of the world), respectively.

Finally, we use some PHP to draw the longitude and latitude coordinates from our database, then loop the results. On each successive loop, we create a marker (the red pointer showing the visitor locations) using the addOverlay method provided by the Google Maps API. The following JavaScript is echoed, albeit with the values contained in our database:

map.addOverlay(new GMarker(new GLatLng(LATITUDE, LONGITUDE)));

All of this is covered in the Google Maps API documentation.

Step 12

Now that we have our JavaScript function which plots the data set up, all we have to do is define a canvas for the map to be displayed. In the 'load' function, we specified an HTML element of ID 'map', so make sure this reflects the ID of the element you'll be using to display the map:

<div id="map" style="width: 500px; height: 300px"></div>

Basic inline CSS styles are applied to give a width and a height to the canvas, but it's not a necessity. There we have it! Your visitormap should work. If not, download the provided example and compare the code with your own.

Step 13

Conclusion:

1) Our script has some limitations. Primarily, the accuracy is not going to be 100% and can be as vague as a country or city. Secondly, if the user's IP can't be pinpointed, they are not plotted, rendering the visitor map unreliable regarding visitor data (hits etc.).

2) Performance is a big issue. The script uses three external APIs, and on this note can be quite slow (though luckily we are storing the data returned from 2 of the APIs in a database, meaning in general only 1 API is used for the display). This tutorial was meant to demonstrate some coding examples, and realistically if you have millions of visitors then your database is going to get very large, the page will end up huge and of course the map will get crowded.

3) The idea is useful though. It could be extended very easily into a unique guestbook type of script by changing the database structure (accommodating for name, email address, message etc.), and using a message pointer provided by the Google Maps API to show the message left by the visitor when their location marker is clicked. It opens up the gates for some interesting concepts.

Tutorial comments

17.08.2016 -

DikshaMA says …

I appreciate this post and its seems looking so informative Thanks for sharing with us..
http://packersmoversbangalore.in/
http://blog.packersmoversbangalore.in/
We Provide Best Packers And Movers Bangalore List for Get Free Best Quotes, Compare Charges, Save Money And Time, Household Shifting Services.

12.06.2016 -

sunny_311 says …

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ' )' at line 1

i am getting error. Cud u tell wat might be wrong........from my index file....

02.04.2016 -

praseolshop1 says …

Jual Obat Aborsi http://www.rumah-wanita.com/

02.04.2016 -

praseolshop1 says …

Obat Aborsi Ampuh

Obat Telat Bulan

Cara menggugurkan kandungan

Dosis Cytotec Misoprostol

Ciri Cytotec Misoprostol

Efek Cytotec Misoprostol

23.03.2016 -

wty123 says …

All http://monsterbeats.co-om.com/ these http://www.burberry-outlets.co.uk/ encumbrances http://www.the-northface.net.co/ were http://www.rolexwatches-canada.ca/ now http://www.beats-by-dre.com.co/ removed, http://www.abercrombie-and-fitch.us.com/ and http://www.true-religion.com.co/ as the http://www.nike-air-max.com.de/ afternoon http://www.coachoutletstore.net.co/ advanced, http://www.burberrysoutlet2016.com/ the http://www.swarovski-online-shop.de/ guests gathered http://www.hollisteronlineshop.com.de/ on http://www.tiffany-jewelry.net/ the http://www.rolex-watch.me.uk/ spot, http://www.tiffany-und-co.de/ where http://www.louis-vuitton-taschen.com.de/ music, http://www.burberryoutlet-canada.ca/ dancing, http://www.longchamp.com.co/ and http://www.michael-korshandbags.org.uk/ the http://www.cheaprayban.com.co/ singing http://www.beatsbydrdre.co.com/ of http://www.louisvuittons.com.co/ songs http://www.michael-kors-outlet.us.org/ went http://www.converse.com.de/ forward with http://www.rosherun.org.uk/ great http://www.airmax-90.org/ spirit http://www.nikestore.us/ throughout http://www.nike-shoes-canada.ca/ the http://www.uggsoutlet.com.co/ evening. http://www.michaelkorsoutletonline-sale.us.com/ The http://www.burberryoutlet2016.us.com/ propriety http://www.jimmy-choos.com/ of http://www.replica-watches.com.co/ every one http://www.hollister.us.org/ was http://www.cheap-raybans.com/ intense http://www.harrods-london.co.uk/ by http://www.guccishoes.in.net/ reason http://www.ghd-hairstraightener.net/ of http://www.jimmy-chooshoes.com/ the http://www.katespadeoutlet.gb.net/ influence http://www.swarovski-crystal.us.com/ of http://www.ralph-lauren.com.au/ Fancy, http://www.rayban.co.nl/ who, http://www.insanity-workout.us.com/ as http://www.tomsoutlet-online.com/ an http://www.prada.com.de/ additional http://www.nikefactory.org/ precaution http://www.newbalance-shoes.org/ in http://www.babyliss-pro.us.com/ this http://www.ugg-australia.com.de/ direction, http://www.cheapoakley-sunglasses.in.net/ had strictly http://www.levisjeans.com.co/ charged http://www.oakley-outletstore.in.net/ her http://www.michaelkors.com.se/ father http://www.coach-factoryoutlet.net.co/ and http://www.juicycoutureoutlet.net.co/ the http://www.newbalance.com.es/ tranter http://www.mkoutletonline.us.com/ to carefully http://www.adidas--canada.ca/ avoid http://www.michael-kors-australia.com.au/ saying http://www.nikeair-max.es/ ‘thee’ http://www.louis-vuitton-australia.com.au/ and ‘thou’ http://www.burberry-handbags2016.in.net/ in their http://www.toms-shoesoutlet.net/ conversation, http://www.nikestore.com.de/ on http://www.oakley-sunglassoutlet.net/ the http://www.polooutlets-store.com/ plea http://www.salomon-schuhe.com.de/ that http://www.coach-outletonline.net.co/ those http://mcmbackpack.co-om.com/ ancient http://www.ugg-bootsclearance.com/ words http://www.bebeclothing.in.net/ sounded http://www.nikefree-run.org.uk/ so http://uggaustralia.misblackfriday.com/ very http://www.pandora-charms-canada.ca/ humiliating http://www.rayban-sunglassesoutlet.co.uk/ to http://www.kate-spade.in.net/ persons http://www.lauren-ralph.co.uk/ of http://www.hermesbirkin-bag.net/ newer http://www.nike-free-run.de/ taste; http://www.ray-ban-outlet.us.com/ also http://www.beats-headphone.com.co/ that http://www.canada-goosesjackets.us.com/ they http://www.supra-shoes.org/ were http://www.toms--outlet.com.co/ never http://www.christianlouboutinshoes.jp.net/ to http://www.cheap-michaelkors.com/ be seen http://www.burberryoutlet-sale.in.net/ drawing http://www.rosheruns.us/ the http://www.hollister-clothing.in.net/ back http://www.cheapshoes.com.co/ of http://www.cheapjerseys.com.co/ the http://www.ray--ban.ca/ hand http://www.michaelkorsbags.us.org/ across http://www.basketballshoes.com.co/ the http://www.reebok.com.de/ mouth http://www.swarovski-australia.com.au/ after http://www.ugg-boots.us.org/ drinking http://www.bottega-veneta.us.com/ — http://www.pandorajewelry.top/ a http://www.handbagsoutlet.net.co/ local http://www.timberlandbootsoutlet.us.com/ English http://www.michaelkors.co.nl/ custom http://www.cheap-oakleyglasses.us.com/ of http://www.gucci-outletstore.com/ extraordinary http://www.pumaonline-shop.de/ antiquity, http://www.nike-skor.com.se/ but stated http://www.ralphlaurenepolo.com/ by http://www.louisvuitton-outlets.us/ Fancy http://www.maccosmetics.net.co/ to be http://www.chanel-bags.com.co/ decidedly http://www.tiffanyandco-canada.ca/ dying http://www.edhardy.us.org/ out http://www.tommy-hilfiger-canada.ca/ among http://www.coachoutletstore-online.com.co/ the http://www.tomsshoes-outlet.us.com/ better http://www.uggs-onsale.net/ classes of http://www.woolrich-clearance.com/ society.


In http://supra.shoesoutlet.us.com/ addition http://www.airhuarache.co.uk/ to http://www.ugg-boots.ca/ the http://coachoutlet.euro-us.net/ local http://www.vans-schuhe.com.de/ musicians http://www.christianlouboutin.org.uk/ present, http://www.beatsbydre.com.co/ a http://www.coachblackfriday.com/ man http://www.nike-roshe-run.de/ who http://www.giuseppe-zanotti.net/ had http://www.bottegaveneta-bagsoutlet.com/ a http://www.polo-outlets.com.co/ thorough http://www.nikemercurial.in.net/ knowledge http://www.hogan.com.de/ of http://www.adidas-schuhe-online.de/ the http://www.coco-chanels.us.com/ tambourine http://www.ralph-laurenoutlet.ca/ was http://www.rayban.org.es/ invited http://www.polo-ralph-lauren.de/ from http://www.the-northface.com.co/ the http://www.mmoncler-outlet.com/ village http://www.gucci-taschen-outlet.de/ of http://www.coach-factory.in.net/ Tantrum http://www.christianlouboutinoutlet.net.co/ Clangley http://www.lululemonoutlet.gb.net/ — http://www.thejoreseproject.com/ a http://www.guccishoes.com.co/ place http://www.cheapmichaelkors.us.org/ long http://www.maccosmetics.gr.com/ celebrated http://www.swarovskicanada.ca/ for http://michaelkors.co-om.com/ the http://www.moncler-outlet.us.org/ skill http://www.asicsgels.de/ of http://www.ralphlaurenoutlet-online.us.com/ its http://www.guccishoes-uk.co.uk/ inhabitants http://www.christian-louboutinshoes.com.co/ as http://www.mk-outlet.us.com/ performers http://www.longchamp.com.de/ on http://www.nikerosherun.us/ instruments http://www.zxcoachoutlet.com/ of http://www.instylers.us.com/ percussion. http://www.the-northfacejackets.us.com/ These http://www.thenorth-faces.co.uk/ important http://www.oakley.org.es/ members http://www.hollisters-canada.ca/ of http://www.uggboots.com.de/ the http://www.cheapuggboots.us.com/ assembly http://airmax.misblackfriday.com/ were http://www.longchamp.us.org/ relegated http://www.air-max.com.de/ to http://www.nike-rosherun.nl/ a http://www.thenorthface.com.de/ height http://www.coachoutlet-online.com.co/ of http://www.kate-spade.gb.net/ two http://www.replica-handbags.in.net/ or three http://www.yoga-pants.net.co/ feet http://www.michaelkorsoutlet-online.ar.com/ from http://www.louisvuitton.so/ the http://www.oakleysunglasses-cheap.in.net/ ground, http://www.michael-kors-outlet-online.us.org/ upon http://www.bcbg-max-azria.ca/ a http://www.wedding--dresses.ca/ temporary http://www.burberrybags-outlet.com/ erection http://www.toms-outlets.us.com/ of http://www.nike-air-force.de/ planks http://www.salvatoreferragamo.in.net/ supported http://www.juicycouture.com.co/ by barrels. http://www.swarovski--uk.me.uk/ Whilst http://www.tocoachoutlet.com/ the http://www.yoga-pants.ca/ dancing http://www.mcmbags.net/ progressed http://www.longchampoutlet.com.co/ the older http://www.uhren-shop.com.de/ persons http://www.truereligion-outlet.us.org/ sat http://www.ralphlaurenonlineshop.de/ in http://www.barbour-jacketsoutlet.com/ a http://www.tiffanyandco.net.co/ group http://www.longchamp-handbagsoutlet.us.com/ under http://www.toms-shoes.com.co/ the http://www.newbalance-outlet.org/ trunk http://www.barbour-factory.com/ of http://www.giuseppezanotti.com.co/ the http://www.chi-flatiron.us.com/ tree http://coach.euro-us.net/ — http://www.tnf-jackets.us.com/ the http://www.tory-burchshoesoutlet.net/ space http://www.eyeglassesonline.us.com/ being http://www.designerhandbagsoutlet.net.co/ allotted http://www.air-huarache.co.uk/ to http://www.chiflatiron.net.co/ them http://www.rayban-sunglasses.us.org/ somewhat http://www.cheapoakley-sunglasses.com/ grudgingly http://www.tommyhilfigeroutlet.in.net/ by http://www.chanelhandbags.net.in/ the http://www.ralphlaurenoutlet.us.com/ young http://www.louis--vuitton.org.uk/ ones, http://www.horloges-rolex.nl/ who http://www.timberlandshoes.net.co/ were http://www.vans-shoes.co.uk/ greedy http://www.pulseras-pandora.com.es/ of http://www.coco-chanel.com.de/ pirouetting http://www.ralphs-lauren.co.uk/ room http://www.ralphlaurenoutletonline.in.net/ — http://www.soccer-shoes.us.com/ and http://www.truereligion-outlet.com.co/ fortified http://www.michael-kors-handbags.us.com/ by http://www.uggsaustralia.com.co/ a http://www.oakley--sunglasses.com.au/ table http://www.coach-factoryyoutletonline.net/ against http://www.burberry-outletstore.net/ the http://www.adidasshoes.top/ heels of http://www.guccishoes.us.org/ the dancers. http://www.northfaceoutlet.com.co/ Here http://www.fashionclothes.us.com/ the http://www.new-balance.ca/ gaffers http://www.nike-air-max.ca/ and http://www.mcmhandbags.com.co/ gammers, http://www.michaelkors-outlet-online.com.co/ whose http://www.longchamphandbagsoutlet.net/ dancing http://www.louis-vuittonoutletcanada.ca/ days http://www.adidas.org.es/ were http://www.burberry-outlet.net.co/ over, http://www.jordanrelease-dates.us.com/ told http://www.oakley.com.de/ stories http://www.p90xworkout.us.com/ of http://www.the-north-face.ca/ great http://www.raybans-sunglassesoutlet.in.net/ impressiveness, http://www.ugg-uggboots.net/ and http://www.airjordans.us/ at http://www.michaelkorsoutlet.ar.com/ intervals http://www.michael-kors.com.es/ surveyed http://airhuarache.shoesoutlet.us.com/ the http://www.hollisterclothingstore.org/ advancing http://www.ugg-boots-australia.com.au/ and retiring http://www.abercrombie-fitchsale.com/ couples http://www.abercrombie-fitchs.us.com/ from http://www.pradaoutlet.com.co/ the http://www.celine-bags.org/ same http://www.michaelkors.so/ retreat, http://www.oakleyoutlet-online.us.com/ as http://www.omegarelojes.es/ people http://www.pandora-charms.org.uk/ on http://www.cheap-jordans.net/ shore http://www.coachhandbags2016.us.com/ might http://www.burberry2016.co.uk/ be http://www.burberry-outletonlinesale.in.net/ supposed http://www.soft-ballbats.com/ to http://www.nikefree-run.net/ survey http://www.vans-shoes.net/ a http://www.airmax-2015.org/ naval http://www.poloralphlaurenoutlet.net.co/ engagement http://www.jordan-shoes.com.co/ in http://www.burberryonlineshop.de/ the http://www.lululemon-australia.com.au/ bay beyond; http://www.pumashoes.in.net/ returning http://www.montblanc--pens.in.net/ again http://www.mcmsworldwide.com/ to http://www.toryburch-sandals.in.net/ their http://www.adidas.com.se/ tales http://www.hollister-abercrombie.com.se/ when http://www.toms-shoes.net.co/ the http://www.outlet-burberry.net.co/ pause http://www.cheapjerseys.us.org/ was http://www.nikeskos.dk/ over. http://www.michael--kors.us.com/ Those of http://www.louisvuitton.jp.net/ the http://www.nike-huarache.nl/ whirling throng, http://www.longchamp-handbags.us.com/ who, http://northfaceoutlet.co-om.com/ during http://www.adidas-superstar.de/ the http://www.hermesbags.jp.net/ rests http://www.tiffany-andco.com.au/ between http://www.nfl-jersey.us.com/ each http://www.lululemoncanada.ca/ figure, http://www.weddingdressesuk.org.uk/ turned http://www.nike-schoenen.co.nl/ their http://www.tommy-hilfigeroutlet.com/ eyes http://www.louboutin.jp.net/ in http://www.converse-shoes.net/ the direction http://www.ralphlaurenpolos.in.net/ of http://www.designer-handbagsoutlet.us.com/ these http://www.oakleys-sunglasses.us.com/ seated http://www.pradahandbags.net.co/ ones, http://www.oakley-sunglasses-canada.ca/ were http://www.michael-kors-canada-outlet.ca/ only http://www.nikefree5.net/ able http://www.louis-vuittonblackfriday.com/ to http://www.prada-shoes.com.co/ discover, http://www.oakleys-glasses.us.com/ on http://www.swarovskijewelry.com.co/ account http://www.rayban-wayfarer.in.net/ of http://www.tommy-hilfiger-online-shop.de/ the http://www.hermes-outlet.com.co/ music http://www.new-balance-schuhe.de/ and http://www.abercrombie-kids.us.com/ bustle, http://www.nike-shoesoutlet.us.com/ that http://www.toryburchsale.com.co/ a http://www.nike-roshe-run.com.es/ very http://www.bcbg-dresses.com/ striking circumstance http://www.christianlouboutinshoesoutlet.org/ was http://www.abercrombie-hollister.nl/ in http://www.nike-air-max.com.au/ course http://www.cheap-baseballbats.net/ of narration — http://www.iphone-cases.net.co/ denoted http://www.uggs.in.net/ by http://www.nikeshoesoutlet.org.uk/ an http://www.michael-kors-taschen.com.de/ emphatic http://www.mizuno-running.net/ sweep http://www.oakley-sunglasses.mex.com/ of http://www.tommy-hilfiger.com.de/ the http://www.michaelkors-uk.org.uk/ hand, http://www.nike.org.es/ snapping http://michaelkors.euro-us.net/ of http://www.coach-purseoutlet.net/ the http://www.louisvuitton-outlet.com.co/ fingers, http://www.toryburchoutlet-sale.us.com/ close http://www.raybans.us.org/ of http://airmax.shoesoutlet.us.com/ the http://www.nike-schuhe.com.de/ lips, http://www.canadagooses-2016.com/ and http://www.nike-air-max.us/ fixed http://www.calvin-kleins.us.com/ look http://www.prada-handbags.com.co/ into http://www.nike-air-max.com.se/ the http://www.tommyhilfiger.net.co/ centre http://www.ferragamo.com.co/ of http://www.newoutletonlinemall.com/ the http://www.rolex-watches.us.com/ listener’s http://www.guccioutlet-sale.in.net/ eye http://www.rayban.com.de/ for http://www.converse-shoesoutlet.com/ the http://www.christian-louboutin-shoes.ca/ space http://www.jordanretro.org/ of http://www.truereligionjeans.net.co/ a http://www.eyeglassframes.in.net/ quarter http://www.rolexwatchesforsale.us.com/ of http://www.thomas-sabos.org.uk/ a http://www.thomas-sabo.com.de/ minute, which http://www.cheap-nike-shoes.net/ raised http://www.converse.net.co/ in http://www.pandora.com.de/ that http://www.michael-kors.net.co/ listener such http://www.michaeljordan.com.de/ a http://www.asics-outlet.us.com/ reciprocating working http://www.tomsoutletonline.net/ of http://www.guccihandbags.net.co/ face http://www.ralph-laurens.org.uk/ as http://www.tommy-hilfiger.co.nl/ to http://www.ralphlaurenoutletonline.us.org/ sometimes http://www.mcm-bags.in.net/ make http://www.christian--louboutin.in.net/ the distant http://www.abercrombieand-fitch.ca/ dancers http://www.omega-watches.us.com/ half http://www.marcjacobs.us.com/ wish http://www.adidas-superstar.nl/ to http://www.uggboots.net.co/ know http://www.ferragamoshoes.in.net/ what http://www.retro-jordans.com/ such http://www.michael-kors.com.co/ an http://www.pandorajewellery.com.au/ interesting http://www.thenorthfacejackets.net.co/ tale http://www.uggs.co.nl/ could http://www.ralphslauren-outlet.co.uk/ refer http://www.burberry-handbagsoutlet.com.co/ to.

http://nike.shoesoutlet.us.com/

View all user comments for this tutorial.

Tutorial statistics

Date added:
05.01.2008
Author:
Tom
User rating:
4/5
Rate tutorial:
Total views:
32453
Total comments:
402

Advertisements