Ramones Baby – Now I Wanna Be a Good Boy

Everyone knows that the Ramones are the best band ever. Well maybe not everyone does, but if you know me and if you know one thing about me, then you probably know that I think that that they are, for sure, by a long shot, the best band ever! So when I found out I was going to become a father, after my initial excitement (and fear), when I settled down and got used to the idea and started to think about what kind of a start in life I wanted to give the little guy, it was only natural that I wanted to introduce and combine everything that I was passionate about so far in my life with the newest and greatest passion I would ever have. The things that inspire me, the things that excite me, the things that shape and define me, I wanted to share it all with him. The authors and stories that fed my imagination and kept the adventures going even hours after I’d put the books down and fallen asleep, my music and the various music genres that came and went through the years (each one leaving its own imprint) versus the ever present theme tunes of my life. Or my sports teams I could lose my mind and my voice over, with the power to make my weekend or destroy my week, all in the space of 90 minutes. Graphic novels, comics, movies, artwork, museums, and cities I’d traveled to and countries I’d lived in. I wanted to share with him everything I’d come across in my life that molded me in some way, all the wonderful things that made the cut.

So of course way up there on that list was the Ramones! Way, way, way up there!

But how do you go about doing that? Does something “Ramonesey” for a kid, or better yet for a baby, even exist? And if it does where can you find it? This is exactly what I asked myself, and this is how I’ve managed to do it:

1. Ramones Teddies

So when I first started searching I figured the most likely thing that would exist would be a Ramones teddy bear. I don’t know why, but I could picture some uber-fan out there that took it upon herself to dress-up a teddy bear in jeans and a biker jacket, with a crazy big black wig and maybe even some rose sunglasses, and sell it to the masses. Well maybe something like that exists out there (and if it doesn’t, it’s a damn good idea which you can have for free, gimme a heads up and I’ll be your first customer!), but I didn’t search long enough to find out. I came across the Ramones Toxic Teddies and my search ended there! These little guys are great, they’re about 3.5” in height and very well detailed, and whilst they really do look like they’re porcelain they’re only plastic, so they look like the real deal whilst they sit there on display but are battle ready to be beat and thrown about when the kid wants to play. This is the first thing I bought for my kid, when he wasn’t but three months in his moms belly, and when I told my cousin I’d bought him something she asked if it was an Iggy music box! Which it could have almost been (again, you can have this idea for free, and I’ll be your first sale!), I love that she knows me so well! And I’m pretty intrigued to see what he does with them when he’s a little older; I used to have Cowboys and Indians figures, Knights and Castles, and Star Wars figures and Transformers. I wonder if the brat will play Ramones with Johnny, Joey, Deedee and Marky?!

2. Ramones Lullabies

This was a present from his uncle Garcia, who had it for a while because we didn’t run into each other, and I could tell he was super excited to give it to me. But I didn’t think it was going to be any big deal. I mean you find out your friend’s having a baby and you buy them a little something, a little token of acknowledgment that you’re excited for them, but really what could be so great about a baby gift? Right? Wrong!!! There is the Ramones Lullabies CD! This is one of the most amazing gifts I have ever been given. I was blown away. I am so glad my baby has this in his life, and I get to put him to sleep listening to some Ramones classic! I will say that it was sort of painful listening to the songs at first, I mean here’s a band known for playing their music four times faster than everyone else, and these songs are like 20 times slower (on the glockenspiel and with no vocals). But it’s all good fun and certainly makes feeding the little guy a bottle in a rocking chair in the corner of a dark room a little more entertaining. And I love that the Ramones are finally getting the respect and notoriety they deserve; the label now has a whole ton of bands lullabyified, but the Ramones was one of the first CD’s they put out.

3. Ramones Onesie

There’s not much to say on this, I mean it’s a frickin Ramones onesie! If you’re a rock-baby and you’re gonna own one onesie then let it be this! The crest of the Ramones – Johnny, Joey, Deedee, Tommy we salute you! And we’ll probably throw up on you too! It’s a little too big for the tyke right now, it’s for 6-12 months and he’s just 3 (awww), but man am I looking forward to getting him in that thing! I bought it from a wicked store near me called Funky 7 that sells the greatest selection of t-shirts, and maybe I could have found a smaller size online somewhere, but I’m happy to support my local community. Oh and I bought Garcia Jr. a Fuel onesie there also (Metallica is to Garcia as Ramones is to me!). Who knows maybe in a few months when Jackson is old enough to wear his onesie he’ll also be ready to upgrade from the lullabies to the originals?! Well at least the slow ballads!

Of course whilst I’m being serious about all this, I’m also being tongue-in-cheek, just like a Ramones song!

Posted May 23rd, 2009

Brine Join the Tribe Campaign

This week was quite exciting for me and my newly formed team here at the agency. We re-launched our client’s website (an incredible feat we pulled off in only 4 weeks from design to launch, but something I’ll talk about in another post) and we launched the digital arm of the new campaign “Join the Tribe”, which in essence is built around the idea of featuring tribal warrior masks built from new 2009 Brine lacrosse products.

Now I must admit that I personally wasn’t involved in conceptualizing the campaign, this was spearheaded by our traditional diversified team back before its digital counterpart (my team – digital diversified) was even officially formalized. And when the campaign arrived on our doorstep and our team had to come up with a way to complement the campaign digitally I still wasn’t involved much as I was committed to other duties (like a project for Ford and um yeah becoming a new dad!). It was pretty obvious that we needed to create an online experience that generated these tribal masks, of course the budget wasn’t quite there to carry out the grandiose idea we originally had, which was pretty damn impressive and involved face recognition to automatically build the tribal masks. So we went back to the drawing board (at which point I was now fully involved) and came up with a more slimmed down version of the application which allows the user to create the mask themselves from a palette of Brine equipment. Now I may be biased at this point, but aside from the initial wow factor that the face recognition technology would have provided, and yes it would be cool if the mask generated really represented the characteristics of your face, but the finished product we’ve come up with where you actually build the mask yourself is pretty damn fun to interact with, and perhaps even, considering the 8-18 year old age range the campaign targets, is a better suited end product. You can check it out here.

So it’s pretty fun to play around with, and I’m proud to be a part of it. You can generate a mask in 3 ways – remix (which gives you a base mask to work from), template (which gives you a stenciled background to work on top of, or just go ahead and start from a blank canvas, and this is after you’ve selected whether you’ll be created a male or female mask (which uses male or female equipment respectively). And once you’re in design mode you can pick the equipment by category (mirror mode can be handy for this), or pick by facial feature (which offers you a mesh of equipment pre created to look like eyes, mouth, nose, etc…).

And when you’re done you can download your mask in a whole bunch of standard sizes (iPhone, chat icon, game icon, screen saver, etc…) and save it to the gallery for all to see.

And of course no digital campaign would be complete without the ad banners to drive traffic to it.

The Tribal Masks app was developed by Honest who did an amazing job with an extremely tight deadline and I am looking forward to working with them again.

Posted May 21st, 2009

Flash Windowless Mode (wmode)

Just over a year ago when we were done ideating the “nextgen” Ford vehicles site and moved into prototyping and early production I put this document together. Disabling wmode had long been the practice of my company and being on the team charged with developing the next generation site we felt that enabling it was a compulsory step to stay competitive with our websites moving forward. It stemmed from a discussion with our multimedia team, I can’t remember now the exact words they used but according to them the whole idea of wmode was a bad hack by the Flash development team many years ago and it was the industry practice to never used it. Until then the Ford site had been a pure Flash site so the issue had never seriously arisen, but our whole strategy moving forward was for the site to be pure HTML (with Flash nuggets) so it was imperative that the we enabled wmode moving forward. My aim was to prove that the idea of wmode being bad was ancient and that it was now the common practice to enable it, which I think I did quite nicely and it hasn’t ever come up again.

I wonder what experiences others have regarding this? Was it your practice to not enable it and you now do? Or maybe you still don’t? Or maybe you never did?

Next Gen and Flash Windowless Mode

What is Windowless Mode?

Windowless Mode (WMODE) enables control over Flash applications within a webpage. It is necessary to enable WMODE to allow JavaScript and CSS to fully control the layout and functionality of a webpage that includes a Flash app. Its main benefits include:

· Stacking – allow the flash object to go on top of some elements but underneath others

· Transparency – show content beneath the flash object

The default WMODE is Window. When a Flash app is in its default mode it actually doesn’t belong to the browser, even though it appears to. It is most efficient for Flash to draw this way and this is the fastest, most efficient rendering mode. The other two are:

· Opaque: Enables stacking

· Transparent: Enables stacking and transparency, is the most processor intense

Examples:

Disabled

http://www.communitymx.com/content/source/E5141/wmodenone.htm

Opaque

http://www.communitymx.com/content/source/E5141/wmodeopaque.htm

Transparent

http://www.communitymx.com/content/source/E5141/wmodetrans.htm

Who has WMODE enabled?

Sample of Alexa.com top 50 ranking sites that have WMODE enabled:

http://www.yahoo.com/ – Transparent

http://espn.go.com/ – Opaque

http://www.cnn.com/ – Transparent

http://www.flickr.com/ – Opaque

http://www.weather.com/ – Opaque

http://dashboard.aim.com/aim – Opaque

http://www.nytimes.com/ – Opaque

https://www.bankofamerica.com/index.jsp – Transparent

http://www.nba.com/playoffs2008/index.html – Transparent

http://www.bbc.co.uk/?ok – Transparent

http://www.cnet.com/ – Transparent

http://www.netflix.com/ – Transparent

http://www.adobe.com/ – Transparent

http://abc.go.com/ – Transparent

Sample of competitor sites:-

http://www.toyota.com/ – Transparent

http://www.chevrolet.com/ – Transparent

http://www.chrysler.com/en/ – Transparent

http://www.audiusa.com/audi/us/en2.html – Opaque

http://www.gm.com/shop/ – Transparent

http://www.hyundaiusa.com/index.aspx – Transparent

http://www.jeep.com/en/ – Transparent

http://www.dodge.com/en/ – Transparent

http://www.bmwusa.com/Default.aspx – Transparent

http://www.ferraristore.com/ – Transparent

http://www.saturn.com/saturn/SaturnIndex.jsp – Transparent

http://www.miniusa.com/#/MINIUSA.COM-m – Transparent

http://automobiles.honda.com/ – Opaque

http://www.mazdausa.com/MusaWeb/displayHomepage.action?bhcp=1 – Transparent

http://www.gmperformanceparts.com/ – Transparent

Known issues

In IE frame count stays current but interval count lags behind:

http://justin.everett-church.com/wmode/

- Only affects user experience if flash requires a high refresh rate, such as games

- Avoid WMODE for these apps

Animation slow and jumpy with slow processors:

- Our sites currently already experience this with the full flash framework without WMODE enabled, though an html version is available

- HTML site will provide more seamless experience with only Flash apps being affected

- Capture slow experience and offer alternative content?

In Firefox text entry fields do not function correctly with international keyboards:

http://www.5etdemi.com/blog/archives/2005/06/firefox-wmodetransparent-is-completely-screwy-and-breaks-textfields/

- Only applies to user input

- Barely applies to sites built to only serve North America

- Make sure input is captured outside of Flash

- Disable WMODE for flash modules requiring input

- Hacks can be applied to the flash is necessary

Mac Firefox Flash disappears when using translucent overlays:

http://www.hedgerwow.com/360/bugs/opacity-disable-flash-on-mac-firefox.html

- Avoid translucent overlays with Flash

- If absolutely necessary use base 64 encoding for translucent image

Screen Readers cannot see Flash when WMODE is enabled:

http://dynamicflash.com/2006/10/flash-accessibility-and-wmode/

- Use html instead of flash for blocks of text

- Make text contained within Flash available outside of Flash

- Current site lacks accessibility and HTML/CSS layout will go a long way to improve this

Supported Browsers and Platforms

All our supported browsers and platforms allow WMODE to be enabled.

Conclusion

It is important to enable WMODE for modern web page design and functionality. We must embrace WMODE to remain competitive. There are negative issues surrounding WMODE but they can be eliminated by being aware of these issues at design and development stage as the majority of our Flash needs are not CPU intensive. The users negatively impacted by WMODE are a tiny minority. Only enable WMODE when necessary, using opaque setting over transparent when possible. If a Flash app is severely affected by WMODE find a seamless way to serve it with WMODE disabled.

Sources

http://www.communitymx.com/content/article.cfm?cid=e5141

Posted May 19th, 2009

Geocoding Part 2 – Import your own Zip Code Spatial Database

In my post yesterday I talked about calculating geographical distances. During my research I’d come across this http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL. It was a super interesting read and helped me get a much better understanding of what it is I am even doing. Also it really helps you gets super optimized with the whole subject, but as the locations table I am working with has less than 3000 entries my queries were already coming back super fast in less than 1000th of a second, so it really didn’t need to be optimized more. I didn’t really have time to mess around and investigate it all, and seeing as I still didn’t really fully understand the whole subject too well it was something I’d come back to at another time if need be. However it did point me to geonames.org that has free databases with geographical data to download. This is incredibly useful and whenever I’ve needed this data in the past I’ve had my client buy it (the disk is like $30 so no biggie, but it seems this might even be the free source they are pulling it all from). They have individual country zip codes files available to export, the US file contains exactly what I needed – all the US zip codes with their respective latitude and longitude coordinates. This site has a whole range of useful features on the subject – they appear to even have their own webservice, and a list client libraries in various languages, which pointed me towards a PHP library that appears to be doing a lot of what I need (but also way more than what I need), but by this point I already have everything I needed and had already spent too much time on the subject (not really but I didn’t have as much time allocated to the subject as it really needs – geo-location is a subject unto itself but only a small piece of the website I am building).

So geonames.org offers a free webservice, but I was already using the google API which is also free so I didn’t see any benefit to switch. But they did offer for free all the zip codes with the geographical coordinates so I decided to import this into my database and cut out the 3rd party google Geocode API. It would mean quicker response time and not having to worry about if the service is unavailable or returning errors, I was actually planning to cache the results locally anyway. And perhaps the zip code table might have to be updated on an annual basis to maintain its accuracy (like do zip codes really change that much anyways?), but the web service API is subject to change and it would be less maintainable to monitor it and react to the changes.

So I downloaded the tab delimited US Zip Codes file and imported it into a table in my database called “tbl_Zipcodes_Spatial”, with the following fields (from the included readme):

Country_code : iso country code, 2 characters
Postal_code : varchar(10)
Place_name : varchar(180)
Admin_name1 : 1. order subdivision (state) varchar(100)
Admin_code1 : 1. order subdivision (state) varchar(20)
Admin_name2 : 2. order subdivision (county/province) varchar(100)
Admin_code2 : 2. order subdivision (county/province) varchar(20)
Admin_name3 : 3. order subdivision (community) varchar(100)
Latitude : estimated latitude (wgs84) float(10,6)
Longitude : estimated longitude (wgs84) float(10,6)
Accuracy : accuracy of lat/lng from 1=estimated to 6=centroid

I created an index on the postal_code field and updated my GeoPos:: prepareGetByDistanceSQL() method to get the zip code from the new table. I actually created a new method so that the class still has the ability to pass in the coordinates to the old method when necessary:

<?php
function prepareGetByDistanceWithZipcodeSQL($zip_code,$distance,$table_name,$fields,$units="miles"){
  $cUnit=self::convertMeasuringUnit($units);
  $sql="
    SELECT ".$table_name.".".implode($fields,",".$table_name.".").",
      tbl_zipcodes_spatial.Latitude AS Zipcode_Latitude,
      tbl_zipcodes_spatial.Longitude AS Zipcode_Longitude,
      ACOS(SIN( PI()* tbl_zipcodes_spatial.Latitude /180 )*SIN( PI()*".$table_name.".Latitude/180 ))+(COS(PI()* tbl_zipcodes_spatial.Latitude /180)*COS( PI()*".$table_name.".Latitude/180) *COS(PI()*".$table_name.".Longitude/180-PI()* tbl_zipcodes_spatial.Longitude /180))* ".$cUnit." AS Distance
    FROM tbl_zipcodes_spatial,".$table_name."
    WHERE
      tbl_zipcodes_spatial.postal_code='".$zip_code."'
      AND ".$cUnit." * ACOS( (SIN(PI()* tbl_zipcodes_spatial.Latitude /180)*SIN(PI() * ".$table_name.".Latitude/180)) +
        (COS(PI()* tbl_zipcodes_spatial.Latitude /180)*COS(PI()*".$table_name.".Latitude/180)*COS(PI() * ".$table_name.".Longitude/180-PI()* tbl_zipcodes_spatial.Longitude /180))
        ) <= ".$distance."
    ORDER BY ".$cUnit." * ACOS(
      (SIN(PI()* tbl_zipcodes_spatial.Latitude /180)*SIN(PI()*".$table_name.".Latitude/180)) +
        (COS(PI()* tbl_zipcodes_spatial.Latitude /180)*COS(PI()*".$table_name.".Latitude/180)*COS(PI() * ".$table_name.".Longitude/180-PI()* tbl_zipcodes_spatial.Longitude /180))
      )
  ";
  return $sql;
}
?>

And it worked! Barely increased the query execution time, and I’ve completely cut out the google API middle man so the overall execution time of the page is greatly increased. Now I feel like I’ve put together something pretty damn robust (the final touch would be to create a stored procedure in the database, and this is something I’ll come back to at a future point). Behold the final script:

<?php
/*
Geographical Location functions
ALL CREDIT GOES TO http://blog.peoplesdns.com/
Thanks to these two blog posts:
http://blog.peoplesdns.com/archives/24
http://blog.peoplesdns.com/archives/34
This API:
http://code.google.com/apis/maps/documentation/geocoding/
And the zipcode database found here:
http://www.geonames.org/
*/

class GeoLoc{

	const GOOGLE_API_KEY="yourgooglekeygoeshere";
	const GOOGLE_API_URL="http://maps.google.com/maps/geo";

	/*
	queries the google api for zip code
	returns long and lat coordinates
	*/
	public function getZipcodeCoordinates($zip_code){
		$result=file_get_contents(self::GOOGLE_API_URL."?q=".$zip_code."&sensor=false&gl=us&output=xml&key=".self::GOOGLE_API_KEY);
		$data=simplexml_load_string($result);
		$coord=$data->Response->Placemark->Point->coordinates;
		$coord=explode(",",$coord);
		$r->longitude=$coord[0];
		$r->latitude=$coord[1];
		return $r;
	}

	/*
	returns the radius
	*/
	public function rad($v){
		return ($v*M_PI/180);
	}

	/*
	degree,minute,seconds to decimal degrees
	note: this could also be done in a single line using ternary
	*/
	public function dms2deg($D,$M,$S,$dir){
		if(strpos(' WsSs', $dir)>0){
			return(-1 * ($D + ($M + $S/60)/60));
		}else{
			return($D + ($M + $S/60)/60);
		}
	}

	/*
	degree,minute,seconds
	*/
	public function dms($rad) {
		$d = abs($rad * 180 / M_PI);
		$d += 1/7200; // add ½ second for rounding
		$deg = floor($d);
		$min = floor(($d-$deg)*60);
		$sec = floor(($d-$deg-$min/60)*3600);
		// add leading zeros if required
		if ($deg< 100) $deg = '0' + $deg;
		if ($deg< 10) $deg = '0' + $deg;
		if ($min< 10) $min = '0' + $min;
		if ($sec< 10) $sec = '0' + $sec;
		return $deg + '\u00B0' + $min + '\u2032' + $sec + '\u2033';
	}

	/*
	gets the measuring unit
	*/
	public function convertMeasuringUnit($units){
		switch ($units){
			case "miles": $r = 3963.191; break;;
			case "nmiles": $r = 3441.596; break;;
			case "kilo": $r = 6378.137; break;;
		}
		return $r;
	}

	/*
	distance between two points using sherical law of cosines
	cos c = cos a cos b + sin a sin b cos C
	*/
	public function distance($lat1, $lon1, $lat2, $lon2, $units = 'miles'){
		$lat1 = self::rad($lat1); $lon1 = self::rad($lon1);
		$lat2 = self::rad($lat2); $lon2 = self::rad($lon2);
		$r=self::convertMeasuringUnit($units);

		return acos(sin($lat1)*sin($lat2) + cos($lat1)*cos($lat2)*cos($lon2-$lon1)) * $r;
	}

	/*
	initial bearing from point 1 to point 2
	*/
	public function bearing($lat1,$lon1, $lat2, $lon2) {
		$y = sin($lon2-$lon1) * cos($lat2);
		$x = cos($lat1)*sin($lat2) - sin($lat1)*cos($lat2)*cos($lon2-$lon1);
		return atan2($y, $x);
	}

	/*
	find out what the midpoint between two points is
	*/
	public function midpoint($lat1, $lon1, $lat2, $lon2) {
		$lat1 = self::rad($lat1); $lon1 = self::rad($lon1);
		$lat2 = self::rad($lat2); $lon2 = self::rad($lon2);
		$dLon = $lon2 - $lon1;
		$Bx = (cos($lat2) * cos($dLon));
		$By = (cos($lat2) * sin($dLon));
		$lat3 = atan2( sin($lat1) + sin($lat2), sqrt( (cos($lat1)+$Bx) * (cos($lat1)+$Bx) + ($By * $By)) );
		$lon3 = $lon1 + atan2($By, cos($lat1) + $Bx);

		if (!$lat3 || !$lon3) return false;
		return array($lat3 * 180 / M_PI, $lon3 * 180 / M_PI);
	}

	/*
	returns sql to query a table for rows by distance (miles,nmiles,kilo)
	table must contain fields named latitude and longitude
	*/
	public function prepareGetByDistanceSQL($long,$lat,$distance,$table_name,$fields,$units="miles"){
		$cUnit=self::convertMeasuringUnit($units);
		$sql="
			SELECT ".implode($fields,",").",
				acos(SIN( PI()* ".$lat." /180 )*SIN( PI()*latitude/180 ))+(cos(PI()* ".$lat." /180)*COS( PI()*latitude/180) *COS(PI()*longitude/180-PI()* ".$long." /180))* ".$cUnit." AS distance
			FROM ".$table_name."
			WHERE active=1
				AND ".$cUnit." * ACOS( (SIN(PI()* ".$lat." /180)*SIN(PI() * latitude/180)) +
				(COS(PI()* ".$lat." /180)*cos(PI()*latitude/180)*COS(PI() * longitude/180-PI()* ".$long." /180))
				) <= ".$distance."
			ORDER BY ".$cUnit." * ACOS(
				(SIN(PI()* ".$lat." /180)*SIN(PI()*latitude/180)) +
				(COS(PI()* ".$lat." /180)*cos(PI()*latitude/180)*COS(PI() * longitude/180-PI()* ".$long." /180))
			)
		";
		return $sql;
	}

	/*
	returns sql to query a table for rows by distance (miles,nmiles,kilo)
	table must contain fields named latitude and longitude
	requires you have the tbl_zipcodes_spatial table http://download.geonames.org/export/zip/
	*/
	public function prepareGetByDistanceWithZipcodeSQL($zip_code,$distance,$table_name,$fields,$units="miles"){
		$cUnit=self::convertMeasuringUnit($units);
		$sql="
			SELECT ".$table_name.".".implode($fields,",".$table_name.".").",
				tbl_zipcodes_spatial.Latitude AS Zipcode_Latitude,
				tbl_zipcodes_spatial.Longitude AS Zipcode_Longitude,
				ACOS(SIN( PI()* tbl_zipcodes_spatial.Latitude /180 )*SIN( PI()*".$table_name.".Latitude/180 ))+(COS(PI()* tbl_zipcodes_spatial.Latitude /180)*COS( PI()*".$table_name.".Latitude/180) *COS(PI()*".$table_name.".Longitude/180-PI()* tbl_zipcodes_spatial.Longitude /180))* ".$cUnit." AS Distance
			FROM tbl_zipcodes_spatial,".$table_name."
			WHERE
				tbl_zipcodes_spatial.postal_code='".$zip_code."'
				AND ".$cUnit." * ACOS( (SIN(PI()* tbl_zipcodes_spatial.Latitude /180)*SIN(PI() * ".$table_name.".Latitude/180)) +
				(COS(PI()* tbl_zipcodes_spatial.Latitude /180)*COS(PI()*".$table_name.".Latitude/180)*COS(PI() * ".$table_name.".Longitude/180-PI()* tbl_zipcodes_spatial.Longitude /180))
				) <= ".$distance."
			ORDER BY ".$cUnit." * ACOS(
				(SIN(PI()* tbl_zipcodes_spatial.Latitude /180)*SIN(PI()*".$table_name.".Latitude/180)) +
				(COS(PI()* tbl_zipcodes_spatial.Latitude /180)*COS(PI()*".$table_name.".Latitude/180)*COS(PI() * ".$table_name.".Longitude/180-PI()* tbl_zipcodes_spatial.Longitude /180))
			)
		";
		return $sql;
	}
}
?>
Posted April 24th, 2009

Geocoding and Distancing and Latitude and Longitude and umm Stuff

Okay this is complicated stuff. Working on putting together a new site for a client, I have a table of locations with longitude and latitude fields for every row (I actually had a tab delimited file, but I sucked it into the db). For the functionality on the web front end a user needs to search by distance, e.g. find all locations within 10 miles of a zip code. Um okay, so how the hell do I do this?

Well first of I need to get the latitude and longitude for a zip code. For that I very quickly found the Google Geocode API and threw together the following:

<?php
$result=file_get_contents("http://maps.google.com/maps/geo?48220&sensor=false&gl=us&output=xml&key=yourgooglekey);
$data=simplexml_load_string($result);
$coord=$data->Response->Placemark->Point->coordinates;
$coord=explode(",",$coord);
$longitude=$coord[1];
$latitude=$coord[0];
?>

It took like 10 minutes, and that included signing up for the API key and reading the documentation, shit this geocoding stuff is easy, I should be done by lunch…

Yeah okay so I have two sets of coordinates, great but errr now what? So I find the Haversine formula, but alas not really being any good at math I don’t understand it, but it doesn’t really matter because I know how to convert it to do the math in PHP. Cool so I got the Haversine function in PHP now but how do I query it against the data in my database? I’d read some stuff about geographical libraries for databases and it seemed super complicated, like the GIS and Spatial extensions for MySQL. So I figure I’ll use a two step approach and do a simple query to pull out a square block of locations and then apply the math. i.e. if I am searching for within a 10 mile radius of a location I’ll do a search on -10 miles and +10 miles, but as the distance is circular I would be getting results in the four corners of that square block that are greater than the 10 miles, and I would then apply the Haversine function and be left only with those results that where truly within the 10 mile radius.

By sheer luck I found this post. It was insane, I didn’t realize you could apply the Haversine formula directly in SQL, I ran that query in my db and bam it worked instantly (well actually there’s a typo syntax error ‘< =’ -blank space between the less than and equals character - in the where clause). Obviously I had to switch out a couple of things so it played nice with my database, but it was instant success, I tried out some different latitude and longitude coordinates and it worked every time:

SELECT Name,Address,Address2,City,State,Zip,Phone,URL,Latitude,Longitude,
acos(SIN( PI()* 42.4584036 /180 )*SIN( PI()*latitude/180 ))+(cos(PI()* 42.4584036 /180)*COS( PI()*latitude/180) *COS(PI()*longitude/180-PI()* -83.1380955 /180))* 3963.191 AS distance
FROM tbl_retailers
WHERE active=1
AND 3963.191 * ACOS( (SIN(PI()* 42.4584036 /180)*SIN(PI() * latitude/180)) +
(COS(PI()* 42.4584036 /180)*cos(PI()*latitude/180)*COS(PI() * longitude/180-PI()* -83.1380955 /180))
) <= 100 ORDER BY 3963.191 * ACOS( (SIN(PI()* 42.4584036 /180)*SIN(PI()*latitude/180)) + (COS(PI()* 42.4584036 /180)*cos(PI()*latitude/180)*COS(PI() * longitude/180-PI()* -83.1380955 /180)) )

Wow so this was it, everything I needed. Oh wait, except that I needed to display the distance in miles. But the guy who blogged this was some kind of superman and he talks about this on another post. Really I only needed the rad() and distance() functions (because distance is dependent on rad), but I decided that they’ll probably all come in useful one day, so I took them wrapped them in a class called GeoLoc. The class doesn’t need to be instantiated into an object so all methods can be called as follows

<?php
GeoLoc::distance($lat1, $lon1, $lat2, $lon2, $units);
?>

Then decided I could abstract in the SQL statement by passing in all necessary variables, and I added it to the class:

<?php
GeoLoc::prepareGetByDistanceSQL($lat,$long,$distance_in_miles,$table_name,$fields);
?>

I then understood that the measuring unit the query is using is the same as in the distance() method so I abstracted it out into its own method. At which point I noticed that the numbers didn’t match exactly – for miles the SQL had 3963.191 whereas the distance function only had 3963.1. I decided that the SQL query had the more granular number and when I reviewed its original blog post it was across the board for all three measuring units so I updated all the numbers. I then figured I might as well abstract in the Google Geocode zip code lookup.

This is what I was left with (functions I’m not using removed); I give all credit to joeldg:

<?php
/*
Geographical Location functions
ALL CREDIT GOES TO http://blog.peoplesdns.com/
Thanks to these two blog posts:
http://blog.peoplesdns.com/archives/24
http://blog.peoplesdns.com/archives/34
This API:
http://code.google.com/apis/maps/documentation/geocoding/
*/
class GeoLoc{

const GOOGLE_API_KEY="yourkeygoeshere";
const GOOGLE_API_URL="http://maps.google.com/maps/geo";

/*
queries the google api for zip code
returns long and lat coordinates
*/
function getZipcodeCoordinates($zip_code){
  $result=file_get_contents(self::GOOGLE_API_URL."?q=".$zip_code."&sensor=false&gl=us&output=xml&key=".self::GOOGLE_API_KEY);
  $data=simplexml_load_string($result);
  $coord=$data->Response->Placemark->Point->coordinates;
  $coord=explode(",",$coord);
  $r->longitude=$coord[0];
  $r->latitude=$coord[1];
  return $r;
}
function rad($v){
  return ($v*M_PI/180);
}
/*
distance between two points using sherical law of cosines
cos c = cos a cos b + sin a sin b cos C
*/
function distance($lat1, $lon1, $lat2, $lon2, $units = 'miles'){
  $lat1 = self::rad($lat1); $lon1 = self::rad($lon1);
  $lat2 = self::rad($lat2); $lon2 = self::rad($lon2);
  $r=self::convertMeasuringUnit($units);
  return acos(sin($lat1)*sin($lat2) + cos($lat1)*cos($lat2)*cos($lon2-$lon1)) * $r;
}
/*
gets the measuring unit
*/
function convertMeasuringUnit($units){
  switch ($units){
    case "miles": $r = 3963.191; break;;
    case "nmiles": $r = 3441.596; break;;
    case "kilo": $r = 6378.137; break;;
  }
  return $r;
}
/*
returns sql to query a table for rows by distance (miles,nmiles,kilo)
table must contain fields named latitude and longitude
*/
function prepareGetByDistanceSQL($long,$lat,$distance,$table_name,$fields,$units="miles"){
  $cUnit=self::convertMeasuringUnit($units);
  $sql="
    SELECT ".implode($fields,",").",
    acos(SIN( PI()* ".$lat." /180 )*SIN( PI()*latitude/180 ))+(cos(PI()* ".$lat." /180)*COS( PI()*latitude/180) *COS(PI()*longitude/180-PI()* ".$long." /180))* ".$cUnit." AS distance
    FROM ".$table_name."
    WHERE active=1
      AND ".$cUnit." * ACOS( (SIN(PI()* ".$lat." /180)*SIN(PI() * latitude/180)) +
    (COS(PI()* ".$lat." /180)*cos(PI()*latitude/180)*COS(PI() * longitude/180-PI()* ".$long." /180))
    ) <= ".$distance."
    ORDER BY ".$cUnit." * ACOS(
    (SIN(PI()* ".$lat." /180)*SIN(PI()*latitude/180)) +
    (COS(PI()* ".$lat." /180)*Cos(PI()*latitude/180)*COS(PI() * longitude/180-PI()* ".$long." /180))
   )
  ";
  return $sql;
}
}
?>
Posted April 23rd, 2009

Customizing Wordpress as a CMS finishing touches

My last couple of posts I’ve talked about how to customize Wordpress to create your own theme and templates. As I talked about in this post I feel that Wordpress is a hugely powerful CMS admin system but falls behind with its front-end publishing capabilities. I don’t like how it publishes the HTML and in this post I will give some hints as to how to completely abandon the Wordpress front-end for your own.

Custom Permalinks
By default all pages are created as something like ‘http://www.mysite.com/?p=14′. But Wordpress has it’s own built-in URL parser and router allowing us to make pretty URLs. Click ‘Settings->Permalinks’ in the left sidebar and select the ‘Month and name’ radio button and hit save (don’t worry about the other options, they really only affect the “posts” URL structure and we’re only concentrating on “pages” here).

It creates an ‘.htaccess’ file in the web root, if Apache doesn’t have permission to create this file then you can create it yourself with the following:

# BEGIN WordPress

RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

# END WordPress

Basically every file that doesn’t exist (media, css, js, etc. files that physically exist bypass the rule) gets sent to the index.php file which does a URL lookup and routes to the correct template.

You can now go and look at a custom page you’ve made and see it has a beautified URL as a Permalink.

Custom Header and Footer
The default Wordpress header and footer does a lot of automatic work. In order to free your code from this I recommend creating you own header and footer. Any functionality that the header and footer contains that you want to keep can be ported over as you need it.

In your theme folder create your own header.php and footer.php files. It’s probably a good idea to save a backup first (even though you’ll probably already have the whole thing backed-up from when you created your own theme, and then get rid of everything in the files you don’t want. For example when I first started experimenting I kept all the boiler plate stuff and ditched the automatic navigation generation and sidebar code. Start with the minimum and work things back in from your template as you need them, if you feel you need them, personally I rewrote everything back in.

Once you understand what you’re doing here you can drop the whole header and footer approach and use a templating engine such as Sigma (which I’ve favored for some time).

Custom Homepage
The final move is to set the homepage as something other that the blog. This is the final key in freeing up Wordpress from being a blog tool dependent on the default code to becoming, well anything you want from a website, backed by a powerful CMS. Of course you will also always have the option to quickly and easily implement a powerful blogging system into your site, but the point is the blog doesn’t actually have to be your site.

In your admin panel create a new page with the title ‘HOMEPAGE’, I recommend to first create a homepage template because a homepage is never like anything else. Once you have that page published navigate to ‘Settings->Reading’ and under the first option ‘Front page displays’ select the second radio button ‘A static page (select below)’, and in the drop-down find the ‘HOMEPAGE’ page you just created, and save your changes.

That’s it, you’re now free to go crazy with your website design and code yet still harness the power that the Wordpress CMS yields! And don’t forget if you want to have a blog in your website, now or in the future, you already have all the tools you could want.

This is part of an ongoing series of posts I am publishing talking about how to use Wordpress as a custom CMS.

Posted April 16th, 2009

Create a custom template in Wordpess

1. Open up a new file and add the following:

<?php
/*
Template Name: My Template
*/
?>

2. Save the file in your theme folder with the name of your new template, the filename doesn’t have to be an exact match for the template name, e.g. ‘mytemplate.php’.

3. In the admin panel create a new page. Give it a title, type in some content, and then in the right sidebar under ‘Attributes’, find your new template in the drop down and select it, and publish the page.

4. When you view your new page on your sites front-end you’ll see a totally blank page. This is good and means it’s worked as we’ve not told the template to do anything yet.

5. Go back to your template file and update it to match the following:

<?php
/*
Template Name: My Template
*/
get_header();

get_footer();
?>

6. Now when you refresh your new page you’ll see the header and footer are now incorporated:

7. That’s great but the content from the CMS is still missing. Add the following into the template file between the get_header() and get_footer() calls, save it and refresh the page:

$thisPage=query_posts("pagename=".$_SERVER["PATH_INFO"]);
echo $thisPage[0]->post_content;

That’s it, you’ve just created your own template! You can now continue to develop out your new template and create more pages using that template, and create more templates.

This is part of an ongoing series of posts I am publishing talking about how to use Wordpress as a custom CMS.

Posted April 3rd, 2009

Create a custom Wordpress theme in one minute

Creating a custom Wordpress theme is damn easy. So easy in fact that when I was originally researching how to do this I didn’t find anything out there that relayed exactly how easy it is. You can find detailed instructions at the official Wordpress documentation, but if you are an experienced web developer and php coder this will give everything you need to immediately hit the ground running.

Assuming you have a working version of Wordpress:

1. Go into your ‘/wp-content/themes/’ folder

2. Copy the ‘classic’ folder and rename it to something that will represent your site (use underscores to separate words and stick with alphabetic characters only – see comment from Ron Fredericks below)

3. In the new folder you just created open the file called ’style.css’

4. In the top of that css file edit the sections within the /* commented out area */. Update ‘Theme Name’, ‘Theme URI’, ‘Description’, ‘Version’, ‘Author’, and ‘tags’ appropriately with your new themes information. (If you can’t think of everything right now don’t worry you can always come back later and change it.)

/*
Theme Name: My Theme
Theme URI: http://www.londonstreetlife.com/
Description: My custom theme.
Version: 1.0
Author: Richard Perry
Author URI: http://blog.londonstreetlife.com/
Tags: Simple gray, two column
*/

5. Create a 300×225 pixels png image with a screenshot of your site, name it “screenshot.png” and overwrite the current one in your theme folder. If you don’t have the design done yet then create an FPO image for the time being, or you can use the one I already made below:

6. Now the fun part. Log into your Wordpress admin section and click Appearance->Themes in the side menu. Now you’re in the themes admin section and you should see the theme you’ve just created under the ‘Available Themes’

7. Clicking either the thumbnail or theme title of your theme will bring up a screen with a demo of your new themes homepage (obviously you haven’t changed anything yet so it will still look life the classic theme.)

8. Hit the ‘Activate’ link top right to set this as your wordpress theme.

That’s it, you’ve just created your own theme! Now you can start making changes to the ’style.css’ file to make it your own.

This is part of an ongoing series of posts I am publishing talking about how to use Wordpress as a custom CMS.

Posted March 30th, 2009

Blake needs to talk to Jack about the homepage…

I found this so funny I literally did Laugh-Out-Loud again and again. It’s just that funny, I have to share it. Fantastic!


Auto Tuning from Casey D on Vimeo.

I wish all the people that I didn’t want to talk to about the homepage were this funny!

Posted March 24th, 2009

Disabling your Twitter background image cleanly

Something that’s frustrating me with the Twitter API is that there seems to be a useful piece of information missing when querying the API for a users settings. There’s a few different ways of pulling this info but http://twitter.com/users/show/ldnstreetlife.xml is as good as any for the purpose of showing you what I’m talking about. The feed contains all the users profile information so we can quite nicely replicate their design in our own app except one vital piece – there is no mention of whether or not the background-image has been disabled. Yes the “profile_background_image_url” node contains the url to the image and the “profile_background_tile” is a boolean which tells us whether or not to tile that background image, but there is also a third option offered in the Twitter design settings which is to disable the background-image altogether, and the API fails to report on this. The problem is it can really make the design look crappy on an account with the background image disabled:

It’s a simple oversight by the API team and one that I’m sure is a dead simple fix when they get around to addressing it. I tried hitting up a couple of the Twitter API coders directly on Twitter with no luck, so I just recently submitted it as a bug http://code.google.com/p/twitter-api/issues/detail?id=370.

In the mean time I wanted to come up with a way to address this issue in my app. More than anything I myself have the background-image disabled in my settings so when I look up myself in my own app it’s ugly. The obvious simple solution was to throw in an exception for myself, but that doesn’t really fly with me.

The second idea I had was something way more complicated. Firstly I’d need to copy over the twelve theme settings into my app. Then I’d be able to cross-reference the users background image with their background color to see if they were using a default image with a custom color. If that were the case it would mean the user had personalized their background color but not their background image, and therefore it was highly likely that the background image had been disabled. At first this seemed like quite a clever idea, it certainly worked in my case where I had disabled my background image and personalized my background color but my background image still remained as one of the default themes. But what if a user had at one point uploaded their own image and then decided to disable it? In that scenario their disabled background image would still be displayed. And then there’s the perhaps more unlikely, but still possible situation where a user has kept the default background image enabled but changed the background color. In that scenario the background image would wrongly not display in my app.

Third time lucky was the obvious, and the one that I settled on as a viable solution while we wait on the API team to amend the feed. It’s basically just to upload an invisible image as your background image in the Twitter display setting – an invisible image being either a transparent gif/png or an image matching your background color (which would obviously be harder to maintain in the long run). I created a 1px x 1px transparent gif and it worked great:

It’s not an across the board solution, it only works if each individual user takes a moment to update the background image in their settings. But for the time being it works great for me, it no longer looks like my page is broke in my own app, and I’m sure the Twitter API team will have this issue resolved in no time. If you also have your background image disabled in your Twitter profile go ahead and re-use my image so you don’t run into the same problem: http://s3.amazonaws.com/twitter_production/profile_background_images/6355571/transparent.gif

Posted March 21st, 2009