Duncan’s blog

November 10, 2011

ColdFusion query-of-queries, tips for adding dynamic columns

Filed under: Coldfusion — duncan @ 5:35 pm
Tags: , , ,

Supposing you’re doing a query of queries, and you want to add a dynamic column, perhaps based on a mixture of existing CF variables and values from the original query. There are a few gotchas to watch out for.

Firstly, you have to use single quotes ‘ ‘ instead of double quotes ” ” for anything in the string. This is contrary to ColdFusion’s normal allowance for any mixture, e.g. this is usually perfectly fine:

<cfset x = "hi" & 'hi'>

However when trying to use ” ” in the query-of-queries, it throws the error:

Query Of Queries syntax error.
Encountered “. Lexical error at line 3, column 25. Encountered: “\”" (34), after : “”

This query will throw that error:

<cfquery name="rstGetStuff" dbtype="query">
	SELECT 	"Hello World" AS columnName
	FROM rstOriginalQuery
</cfquery>

But this is fine:

<cfquery name="rstGetStuff" dbtype="query">
	SELECT 	'Hello World' AS columnName
	FROM rstOriginalQuery
</cfquery>

Secondly, if you’re wanting to refer to variables within that string, just add them into the string surrounded by # #. Again, contrary to normal CFML, where these are equivalent:

<cfset x = "hi " & variables.strName>
<cfset x = "hi #variables.strName#">

So this throws the error:

Query Of Queries syntax error.
Encountered “.. Incorrect Select Statement, Expecting a ‘FROM’, but encountered ‘.’ instead, A select statement should have a ‘FROM’ construct.

<cfset strName = "Duncan">

<cfquery name="rstGetStuff" dbtype="query">
	SELECT 	'Hello ' + strName AS columnName
	FROM rstOriginalQuery
</cfquery>

Instead you have to do

<cfquery name="rstGetStuff" dbtype="query">
	SELECT 	'Hello #strName#' AS columnName
	FROM rstOriginalQuery
</cfquery>

Thirdly, if you’re wanting to add values from the original query into that dynamic column, you might need to CAST it to the correct type. In this case I have a column in the original query, intIDColumn, that is a numeric ID.

This throws the error:

Query Of Queries runtime error.
Cannot mix types INTEGER and VARCHAR in a + binary operation.

<cfquery name="rstGetStuff" dbtype="query">
	SELECT 	'/some/url/path/' + intIDColumn + '/' AS strURL
	FROM rstOriginalQuery
</cfquery>

Instead I have to cast it to a VARCHAR when trying to add it into my string.

<cfquery name="rstGetStuff" dbtype="query">
	SELECT 	'/some/url/path/' + CAST(intIDColumn AS VARCHAR) + '/' AS strURL
	FROM rstOriginalQuery
</cfquery>

November 4, 2011

Google Maps API – adding infowindows in response to user clicks

In response to my previous post about adding infowindows with the Google Maps API, Frank B asked if it was possible “to write a script where the user clicks on the map, and an infowindow pops up in that location containing information about that place, say the county it belongs to”. Here’s a quick something I rustled up in response to that.

Firstly, let’s just open an infowindow on a map in response to user clicks on the map.

<script type="text/javascript">
function initialize() {
	var myOptions = {
		zoom: 10,
		center: new google.maps.LatLng(50.820645,-0.137376),
		mapTypeId: google.maps.MapTypeId.ROADMAP
	};
	
	var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
	
	var infowindow =  new google.maps.InfoWindow({
		content: 'Hello World!'
	});

	google.maps.event.addListener(map, 'click', function(event) {
		infowindow.setPosition(event.latLng);
		infowindow.open(map);
	}); 
}

google.maps.event.addDomListener(window, 'load', initialize);
</script>

So we simply have an event listener for any click events on the map itself. We can then find out the position of that click using event.latLng, which we can then pass to the setPosition function on the infowindow. The final .open() simply shows the infowindow; if it’s already open, this won’t do anything (but it causes no harm to call it again).

This opens the same infowindow anywhere we click on the map:

Now, let’s get some content about each location we click on, and use that to dynamically set the content of the infowindow. To do this we need to do a reverse Geocoding request (i.e. getting address details from a latlng coordinates). The usual use of the Geocoding service is to do the opposite – find out the coordinates of an address.

Interestingly Google’s API reference says to use a ‘location’ parameter but their Developer documentation says to use a ‘latLng’ parameter. Both seemed to work for me, but I’d say the API reference should be considered the correct source in general.

<script type="text/javascript">
var map, geocoder, infowindow;
	
function initialize() {
	var myOptions = {
		zoom: 10,
		center: new google.maps.LatLng(50.820645,-0.137376),
		mapTypeId: google.maps.MapTypeId.ROADMAP
	};
	
	map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
	
	geocoder = new google.maps.Geocoder();
	
	infowindow =  new google.maps.InfoWindow({
		content: ''
	});

	google.maps.event.addListener(map, 'click', function(event) {
		doGeocoding(event.latLng);
	});
}

function doGeocoding(latLng) {	
	geocoder.geocode({'location': latLng}, function(results, status) {
		if (status == google.maps.GeocoderStatus.OK) {
			if (results[1]) {	// use 2nd array item, a less-specific address
				infowindow.setContent(results[1].formatted_address);
			} else {
				infowindow.setContent('');
			}
		} else {
			infowindow.setContent('no address found');
		}
	});
	
	infowindow.setPosition(latLng);
	infowindow.open(map);
}

google.maps.event.addDomListener(window, 'load', initialize);
</script>

This code does strange things for me when clicking on the area at sea. If it’s the first click on the map, it doesn’t display any infowindow at all. If I initially click on the land to get an address, subsequent clicks on the sea use that same address, unless I click further out from the land, in which case it gives me ‘no address’. Think it’s an issue with trying to do setContent(”). I’m publishing this article despite it not being quite code-complete, in the hope it helps Frank (and I’m happy to take suggestions on how to get it fully working as it should).

October 8, 2011

Google Maps API – infowindows

So previously I showed how to create a basic map, then how to add markers to it. Now suppose you’re wanting to have one of those little bubbles pop up when you click on your map with some information in it. These are called infowindows in Google’s terminology.

Let’s start with the very basics – creating a map which has an infowindow already visible on it.

function initialize() {
	var homeLatlng = new google.maps.LatLng(51.476706,0);

	var myOptions = {
		zoom: 15,
		center: homeLatlng,
		mapTypeId: google.maps.MapTypeId.ROADMAP
	};

	var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);

	var infowindow =  new google.maps.InfoWindow({
		content: 'Hello World!',
		map: map,
		position: homeLatlng
	});
}

google.maps.event.addDomListener(window, 'load', initialize);

So we create an infowindow, specify some content for it and which map it’s for, and give it a latlong position (which coincidentally also happens to be where I’ve specified this map is to be centered, although that doesn’t have to be the case). The documentation says that “After constructing an InfoWindow, you must call open to display it on the map“; however I find the above code will open the infowindow without needing to explicitly call the open function.

But this shows the infowindow immediately. Perhaps you’d rather it only appeared after some user interaction. Typically you’d put markers on the map, and when the user clicks the marker, then you’d show the infowindow.

So let’s create the infowindow slightly differently. This time, don’t specify the position attribute. Then create a marker as normal, and finally we can open the infowindow, and we pass the marker as the second parameter. So the infowindow gets anchored to the marker’s position.

var infowindow =  new google.maps.InfoWindow({
	content: 'Hello World!',
	map: map
});

var marker = new google.maps.Marker({
	position: homeLatlng, 
	map: map
});

infowindow.open(map, marker);

So we’ve now added a marker to the map, which the infowindow is then anchored to.

You probably only want this to happen after the user has clicked on that marker. For that we need to have an event listener function. There are many of these available for all the different map elements, in this case we want to listen to the mouseclick event on that marker.

google.maps.event.addListener(marker, 'click', function() {
	infowindow.open(map, this);
});

So we say to the Google Maps event handler framework, on the marker, listen for any ‘click’ events. And when that happens, call this anonymous function which currently only has one line, to open the marker.

We could also make this infowindow appear in response to other events, e.g. if you simply hovered the mouse over the marker.

google.maps.event.addListener(marker, 'mouseover', function() {
	infowindow.open(map, this);
});

And then to make the infowindow disappear again when you move the mouse away from the marker, just call the close() function on mouseout.

google.maps.event.addListener(marker, 'mouseout', function() {
	infowindow.close();
});

Suppose you had several markers on your map, each of which would have its own infowindow. Here’s one way to deal with that. Firstly have an array of everything you need for each marker, arrDestinations. Then loop over them, adding a marker for each. We only have one infowindow variable, and we just update the content for it in response to user clicks. We need to delegate the event handler to an external function, bindInfoWindow, otherwise you end up just getting the content of the last array item for each marker.

<script type="text/javascript">
function initialize() {
	var i;
	var arrDestinations = [
		{
			lat: 50.815155, 
			lon: -0.137072, 
			title: "Brighton Pier", 
			description: "Brighton Palace Pier dates to 1899"
		},
		{
			lat: 50.822638, 
			lon: -0.137361, 
			title: "Brighton Pavilion", 
			description: "The Pavilion was built for the Prince of Wales in 1787"
		},
		{
			lat: 50.821226, 
			lon: -0.139372, 
			title: "English's", 
			description: "English's Seafood Restaurant and Oyster Bar"
		}
	];
	
	var myOptions = {
		zoom: 15,
		center: new google.maps.LatLng(50.820645,-0.137376),
		mapTypeId: google.maps.MapTypeId.ROADMAP
	};
	
	var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
	
	var infowindow =  new google.maps.InfoWindow({
		content: ''
	});
	
	// loop over our array
	for (i = 0; i < arrDestinations.length; i++) {
		// create a marker
		var marker = new google.maps.Marker({
			title: arrDestinations[i].title,
			position: new google.maps.LatLng(arrDestinations[i].lat, arrDestinations[i].lon),
			map: map
		});
		
		// add an event listener for this marker
		bindInfoWindow(marker, map, infowindow, "<p>" + arrDestinations[i].description + "</p>");  
	}
}

function bindInfoWindow(marker, map, infowindow, html) { 
	google.maps.event.addListener(marker, 'click', function() { 
		infowindow.setContent(html); 
		infowindow.open(map, marker); 
	}); 
} 

google.maps.event.addDomListener(window, 'load', initialize);
</script>

In production you’d probably use a server-side language to populate the array and just pass it into the initialize function. There are other ways of doing this as well. Another approach is to have multiple infowindows, one for each marker. On click, you close any open infowindows, and then just open the one that corresponds to the current marker. I don’t believe that approach is as efficient as my example though.

September 25, 2011

Google Maps API – adding markers

I previously showed how to create a very simple map. But usually you’ll want to do more than that. Let’s start with adding markers to the map.

So, using the code from the previous post, I just add this to the end of the initialize function:

var homeMarker = new google.maps.Marker({
	position: homeLatlng
});

That’s all you need to create a Marker object! There are many other attributes you can specify here, but only position is required.

But you’ll notice that using this code, no marker will be visible. That’s because we haven’t said what map this marker is for. Sometimes you might want to deliberately do this, e.g. by creating markers in advance for showing/hiding dynamically later on.

So there are two ways to associate a marker with a map. When you create the Marker object, just specify the map attribute. The value of which should refer to the variable name you used when you created the Map object.

var homeMarker = new google.maps.Marker({
	position: homeLatlng,
	map: map
});

Alternatively, you can call the setMap() function:

homeMarker.setMap(map);

If you ever wanted to remove a marker from a map, just call marker.setMap(null).

So at this point you’ve got a map that looks something like this (showing the brilliantly-titled No Name Key in Florida):

Great, right? Well maybe you want to do just a bit more than that. Let’s examine some of the other options.

Firstly, you can specify a title. This will be displayed as a tooltip when you mouse-over the marker.

var homeMarker = new google.maps.Marker({
	position: homeLatlng,
	map: map,
	title: "Check this cool location"
});

Maybe you’re not keen on that shadow. Easy, just set the flat property or use the marker.setFlat() function:

var homeMarker = new google.maps.Marker({
	position: homeLatlng,
	map: map,
	title: "Check this cool location",
	flat: true
});

Perhaps you need users to be able to drag the markers around (this will come in useful later if you’re doing more advanced dynamic things on the map). Simple, just set the draggable property or use the marker.setDraggable() function:

var homeMarker = new google.maps.Marker({
	position: homeLatlng,
	map: map,
	title: "Check this cool location",
	draggable: true
});

Fantastic. But supposing you’re not keen on the default marker image? Not a problem. Google have lots of different marker images you can use:

To use one of these images, just specify the icon property when creating the marker, or use the marker.setIcon() function. You can use either an absolute or relative URL (for images you’re hosting yourself).

var homeMarker = new google.maps.Marker({
	position: homeLatlng,
	map: map,
	title: "Check this cool location"
	icon: "http://maps.google.com/mapfiles/ms/micons/blue.png"
});

One difference you’ll notice from when we just used the default image, is that no shadow is displayed underneath the marker. You might not care, although it’s a nice visual touch that gives the map a bit of depth. If you want to specify a shadow, you need to have a shadow image as well. This is the shadow image for the Google markers:

One way to setup a shadow is just specify the shadow property on the MarkerOptions, or use marker.setShadow().

var homeMarker = new google.maps.Marker({
	position: homeLatlng,
	map: map,
	title: "Check this cool location",
	icon: "http://maps.google.com/mapfiles/ms/micons/blue.png",
	shadow: "http://maps.google.com/mapfiles/ms/micons/msmarker.shadow.png"
});

However this doesn’t actually place the shadow in the correct location for the above example (see image on the right). I think it’s important to understand what’s happening here.
The marker image is 32 x 32 pixels in dimensions. The shadow image is also 32 pixels high, but is wider, 59 pixels. Both images are currently being centred horizontally on the same point on the map.

Shadow:

Marker:

Together:

What we need to do is create MarkerImage objects for both the marker and its shadow, which will allow us to offset the shadow image to be slightly more to the right, so that it lines up nicely with the marker.

var image = new google.maps.MarkerImage(
	'http://maps.google.com/mapfiles/ms/micons/blue-dot.png',
	new google.maps.Size(32, 32),	// size
	new google.maps.Point(0,0),	// origin
	new google.maps.Point(16, 32)	// anchor
);

var shadow = new google.maps.MarkerImage(
	'http://maps.google.com/mapfiles/ms/micons/msmarker.shadow.png',
	new google.maps.Size(59, 32),	// size
	new google.maps.Point(0,0),	// origin
	new google.maps.Point(16, 32)	// anchor
);

So what’s going on here? We define the URL of the image, then the size of the image (width,height). Then the origin, which is the x,y coordinates of where our marker starts on that image (useful if you’re using one sprite image to do lots of markers). The origin locates the top-left corner of our marker. The anchor is the important one here for lining up our marker and our image. This is where the image ‘anchors’ itself to our latlng coordinates on the map. So as the marker comes to a point half-way along it, we say it’s 16 pixels along and 32 points down (i.e. at the bottom of the image). We then repeat this with the shadow, where the tip of the shadow is also 16 pixels along that image, coincidentally.

We then attach the icon and its shadow to the marker like so:

var homeMarker = new google.maps.Marker({
	position: homeLatlng,
	map: map,
	title: "Check this cool location",
	icon: image,
	shadow: shadow
});

You can also get markers from other sources, e.g.

Finally, here’s the complete code showing how to add custom marker images as outlined above:

<!DOCTYPE html>
<html>
<head>
<title>Google Maps API V3 lesson 2</title>

<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<style type="text/css">
html { height: 100% }
body { height: 100%; margin: 0; padding: 0 }
#map_canvas { height: 300px; width:600px }
</style>

<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>

<script type="text/javascript">
	function initialize() {
		var homeLatlng = new google.maps.LatLng(24.696554,-81.328238);

		var myOptions = {
			zoom: 15,
			center: homeLatlng,
			mapTypeId: google.maps.MapTypeId.ROADMAP
		};

		var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);

		var image = new google.maps.MarkerImage(
			'http://maps.google.com/mapfiles/ms/micons/green-dot.png',
			new google.maps.Size(32, 32),	// size
			new google.maps.Point(0,0),	// origin
			new google.maps.Point(16, 32)	// anchor
		);

		var shadow = new google.maps.MarkerImage(
			'http://maps.google.com/mapfiles/ms/micons/msmarker.shadow.png',
			new google.maps.Size(59, 32),	// size
			new google.maps.Point(0,0),	// origin
			new google.maps.Point(16, 32)	// anchor
		);

		var homeMarker = new google.maps.Marker({
			position: homeLatlng, 
			map: map,
			title: "Check this cool location",
			icon: image,
			shadow: shadow
		});
	}

	google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
	<div id="map_canvas"></div>
</body>
</html>

September 21, 2011

ColdFusion LSCurrencyFormat inserts hard spaces?

Filed under: Coldfusion — duncan @ 8:31 pm
Tags: , , , , , ,

Today I was doing some work with the LSCurrencyFormat function for the very first time. Along the way I discovered something slightly unexpected. If the locale you specify uses spaces for a thousands separator (e.g. French), then Adobe ColdFusion (no idea for Railo or BlueDragon), doesn’t just add a normal space, it uses a ‘hard’ space.

I wouldn’t have found this out at all if it wasn’t for the fact I was doing some unit tests with MXUnit at the time. My test case was something like this:

<cfset strPrice = lsCurrencyFormat("12345678.9", "none", "fr_FR")>
<cfset assertEquals("12 345 678,90",  strPrice)>

So initially that failed, giving me the useful message that
Expected ’12 345 678,90′ but received ’12 345 678,90′. These values should be the same.
Puzzling. I was doing this in Firefox; if I selected just the error message and then chose View Selection Source, I could see it actually said
Expected ’12 345 678,90′ but received ’12&nbsp;345&nbsp;678,90′.

Ahah, so I assumed it was inserting the ‘&nbsp;’ non-breaking space HTML entity into the value instead of just a normal single space. So I updated my unit test assertion to be like this:

<cfset assertEquals("12&nbsp;345&nbsp;678,90",  strPrice)>

But that also failed, and this time when checking the source, it said
Expected ’12&nbsp;345&nbsp;678,90′ but received ’12&nbsp;345&nbsp;678,90′.
Curiouser and curiouser!

So at this point, I decided to loop over the actual string returned by lsCurrencyFormat to examine it more closely:

<cfoutput>
	<cfset french = lsCurrencyFormat("12345678.90", "none", "fr_FR")>
	
	<cfloop index="i" from="1" to="#Len(french)#">
		<cfset char = mid(french, i, 1)>
		
		#char#:#Asc(char)#<br/>
	</cfloop>
</cfoutput>

Which produced output that looked like:

1:49
2:50
 :160
3:51
4:52
5:53
 :160
6:54
7:55
8:56
,:44
9:57
0:48

The normal HTML space is ASCII character 32. But in this case it’s inserting ASCII character 160, which the browser interprets as &nbsp;. So for my unit test to work, I’ll have to do something like:

<cfset assertEquals("12" & Chr(160) & "345" & Chr(160) & "678,90",  strPrice)>

Dunno why Adobe in their infinite wisdom (to be honest this probably dates back to Allaire or Macromedia) would use character 160 instead just a normal single space character 32. And I expect other locale-specific formatting functions must do the same thing.
I’m getting exactly the same results with java.text.DecimalFormatSymbols.getGroupingSeparator(), so I expect ColdFusion is using that functionality in the background.

I suppose it shouldn’t really cause any problems, apart from perhaps when you’re needing to unit test (or perhaps if parsing some HTML you’ve received by CFHTTP). Just, unexpected is all.

September 19, 2011

Adobe survey

Filed under: Coldfusion — duncan @ 6:57 pm
Tags: , ,

I was sent a link to a survey on behalf of Adobe, asking about use of ColdFusion. The website the survey is on doesn’t get off to a promising start:

uh, ok. So I proceed to the next page, which made me swear out loud.

Yes, that’s right, that bit in the blue text at the bottom, scrolling along the page, it’s the <marquee> tag in use! And not even ironically. It’s like 1999 all over again…

<p><span class="style1">
  <marquee>
  This survey is best viewed with Internet Explorer
  </marquee>
</span></p>

I ended up giving up on it fairly quickly after that.

September 18, 2011

Google Maps API – an introduction

This is the first in a series of posts I intend to do looking into some uses of the Google Maps Javascript API, V3. Let’s start at the very beginning – you want to display a map on a webpage, so what’s required. This is the bare minimum you need to do.

Add an empty <div> to your HTML page, with a suitable ID attribute:

<div id="map_canvas"></div>

Add some CSS like this:

<style type="text/css">
html { height: 100% }
body { height: 100%; margin: 0; padding: 0 }
#map_canvas { height: 100% }
</style>

Include the Google Maps javascript file:

<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>

Create a javascript function that includes all the next few lines of code; let’s stick to convention and call it initialize.

Create a latlong object which indicates the latitude and longitude where your map is centred:

var homeLatlng = new google.maps.LatLng(51.42838,0.0); // London

If you don’t already know the latitude and longitude for where you want to place your map, there’s a very easy way to find out:

  1. Go to Google Maps
  2. Search for your desired destination, and zoom right in
  3. Right-click on the map at your destination, and choose the “What’s here?” option
  4. The latitude and longitude coordinates will appear in the search box

Create a structure with the following properties:

var myOptions = {
	zoom: 10,
	center: homeLatlng,
	mapTypeId: google.maps.MapTypeId.ROADMAP
};

The zoom value can be any integer between 0 (fully zoomed out) and about 18. Some cities will support zoom up to about 20, and there are isolated cases of parts of maps having a zoom level up to 23 or more! In general though you won’t want to zoom in that far. Typically I’d set this around 7 – 15 depending on what kind of map I’m displaying.

The center value uses the latlong object you already created.

The mapTypeId value can be one of four options:

  1. google.maps.MapTypeId.ROADMAP – normal street map
  2. google.maps.MapTypeId.SATELLITE – satellite photos (might not be available for all locations if you’re zoomed in too far)
  3. google.maps.MapTypeId.HYBRID – combination of a satellite map with streets overlaid on top
  4. google.maps.MapTypeId.TERRAIN – what it sounds like, indicates natural features, height of land etc

I generally stick with ROADMAP, as that’s the most typical map type you see by default. Here’s a demonstration of the different types:

Create a new map with the structure of options you just created, and specifying the DIV where you want the map to appear:

var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);

That’s the end of your initialize function. You could just call this using the onload attribute of the body tag. Or if you were using jQuery, with $(document).ready(). However, Google has an event listener, that does the same thing:

google.maps.event.addDomListener(window, 'load', initialize);

Wrapping it all up, here’s the complete page for simply displaying a map at a given location:

<!DOCTYPE html>
<html>
<head>
<title>Google Maps API V3 lesson 1</title>

<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<style type="text/css">
html { height: 100% }
body { height: 100%; margin: 0; padding: 0 }
#map_canvas { height: 100% }
</style>

<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>

<script type="text/javascript">
	function initialize() {
		var homeLatlng = new google.maps.LatLng(51.476706,0); // London
		
		var myOptions = {
			zoom: 15,
			center: homeLatlng,
			mapTypeId: google.maps.MapTypeId.ROADMAP
		};
		
		var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
	}
	
	google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
	<div id="map_canvas"></div>
</body>
</html>

September 17, 2011

Using jQuery to animate table rows

Filed under: Javascript,jQuery — duncan @ 8:00 am
Tags: , , ,

jQuery has some nice ways to animate content, e.g. sliding or fading it into view. These don’t really work on <tr> or <td> tags though. I had a situation recently where we wanted to add an extra <tr> into a table, and make it slide in. The answer’s very simple (thanks to stackoverflow) – wrap the table content in a div, and add the slide animation to that instead.

So imagine you have a very simple example table like this:

<table>
	<tr id="row1">
		<td><a href="">Show another row</a></td>
	</tr>
</table>

This javascript would then make the second <tr> slide into view.

<script type="text/javascript">
$(document).ready(function() {
	// hidden content to add after the current row
	$('#row1').after("<tr id='row2'><td><div style='display:none'>There's a voice that keeps on calling me. Down the road, that's where I'll always be. Every stop I make, I make a new friend. Can't stay for long, just turn around and I'm gone again. Maybe tomorrow, I'll want to settle down, Until tomorrow, I'll just keep moving on.</div></td></tr>");

	$('#row1 a').click(function() {
		if ($('#row2 div').is(":visible")) {
			// hide the div
			$('#row2 div').slideUp(700);
			
		} else {
			// slide the div into view
			$('#row2 div').slideDown(700);
		}
		
		// prevent the click on the link from propagating
		return false;
	});
});
</script>

Of course it gets more complicated if you have more than one <td>. For example:

<table>
	<tr id="row1">
		<td>A</td>
		<td>One</td>
		<td>Red</td>
		<td>Apple</td>
		<td>$0.99</td>
		<td><a href="">Show row 2</a></td>
	</tr>
</table>

In that case you can use the .wrapInner function to add a hidden div to all the <td> tags.

<script type="text/javascript">
$(document).ready(function() {
	// content to add after the current row
	var $row2 =	$('<tr id="row2">' +
					'<td>B</td>' +
					'<td>Two</td>' +
					'<td>Yellow</td>' +
					'<td>Banana</td>' +
					'<td>$1.23</td>' +
					'<td> </td>' +
				'</tr>');
	
	// add hidden divs around the content of all the TD tags
	$row2.find('td').wrapInner('<div style="display:none" />');
	
	// add this row after the first row
	$('#row1').after($row2);

	$('#row1 a').click(function() {
		if ($('#row2 div').is(":visible")) {
			// hide the div
			$('#row2 div').slideUp(700);
			
			// update link text
			$('#row1 a').text('show row 2');
			
		} else {
			// slide the div into view
			$('#row2 div').slideDown(700);
			
			// update link text
			$('#row1 a').text('hide row 2');
		}
		
		// prevent the click on the link from propagating
		return false;
	});
});
</script>

June 19, 2011

Project Euler problem 26

Filed under: Project Euler,Python — duncan @ 9:27 pm

Problem 26:

A unit fraction contains 1 in the numerator. The decimal representation of the unit fractions with denominators 2 to 10 are given:

1/2 = 0.5
1/3 = 0.(3)
1/4 = 0.25
1/5 = 0.2
1/6 = 0.1(6)
1/7 = 0.(142857)
1/8 = 0.125
1/9 = 0.(1)
1/10 = 0.1

Where 0.1(6) means 0.166666…, and has a 1-digit recurring cycle. It can be seen that 1/7 has a 6-digit recurring cycle.

Find the value of d < 1000 for which 1/d contains the longest recurring cycle in its decimal fraction part.

Another one I initially attempted with ColdFusion, but it didn’t give decimals to enough precision (at least without using the underlying Java), so turned to Python.

To me this seemed like a good place to use a regular expression, where you can match a group and any repetitions of it, using back-references. Some problems around which parts should be greedy or not. For instance if you have 0.01010101 is the repeating pattern 0101 twice, or 01 four times?

Here’s the regular expression I used:

“^0\.[0-9]*([0-9]{7,}?)\1+[0-9]*?$”

And here’s an explanation of the various parts of it:

^0\.[0-9]*([0-9]{7,}?)\1+[0-9]*?$

The ^ matches the beginning of the string, and the $ matches the end of the string. They’re not always strictly necessary, but it can be good practice for examples like this.

^0\.[0-9]*([0-9]{7,}?)\1+[0-9]*?$

The value is 1/d. As d starts at 2 and increases to 1000, the value starts at 0.5 and gets closer and closer to zero. So the value is always going to start with a zero. Normally a . in a regular expression indicates ‘any character’. The \. just tells the regular expression engine to ‘escape’ it and treat it as a string literal, not a regex special character.

^0\.[0-9]*([0-9]{7,}?)\1+[0-9]*?$

[0-9] just means match any digit between 0 and 9. The * means 0 or many. Notice this is before the part in the ( ) that I’m really interested in. So in other words, there may be some digits before the pattern. e.g. for 1/6, which is 0.166666… I don’t care about that first digit 1.

^0\.[0-9]*([0-9]{7,}?)\1+[0-9]*?$

The ( ) is a way of grouping parts of a regex, in this case for the benefit of back-referencing.
The fact we’re given a 6 digit example means we can assume the answer has to be at least 7 digits. So I used the {7,} syntax to mean the group has to be a minimum of 7 digits long.
The ? means 0 or 1. In other words, only give me up to 1 matching group that is a minimum of 7 characters long, and don’t be greedy!

^0\.[0-9]*([0-9]{7,}?)\1+[0-9]*?$

The \1 is a back reference to the earlier grouped part. If there were multiple parts each with their own ( ) you could back-reference them with \2, \3 etc.
And the + means 1 or more, so there has to be at least 1 repeating group.

^0\.[0-9]*([0-9]{7,}?)\1+[0-9]*?$

The final [0-9] is for any trailing digits that don’t fit the pattern. Even though once the pattern starts in theory it continues infinitely, in reality you might get a value that is rounded, e.g. where you have 0.16666667 instead of 0.16666666…
The * means zero or many of these trailing digits, and the ? stops it from being greedy. Interestingly, you’d assume that just the ? on its own would be more efficient, as that extra digit is just going to be one optional digit and no more. But that reduces the performance somewhat.

And here’s the complete code.

import re
from decimal import *

def displaymatch(match):
    if match is None:
        return 0
   
    return len(match.group(1))
    
                                  
length = 0
maxlen = 0
d = 0
getcontext().prec = 2000

for i in range(1,1000):
    fraction = 1/Decimal(i)
    pattern = re.search(r"^[0-9]\.[0-9]*([0-9]{7,}?)(\1+)[0-9]*?$", str(fraction))
    
    length = displaymatch(pattern)

    if length > maxlen:
        maxlen = length
        d = i

print(d)

I’m using the Python regular expression and Decimal libraries. I also had to increase the precision of the decimal context to up to 2000, as lower values were giving me incorrect answers. i.e. it was truncating the fraction a bit, which meant my pattern matching wasn’t finding the correct answer. So by increasing the precision, I increased the length of the fraction being returned, and therefore improved the chances of finding the correct answer.

September 16, 2010

cfdump label attribute

Filed under: Coldfusion — duncan @ 9:06 pm
Tags: , ,

The <cfdump> tag in ColdFusion has an optional label attribute which doesn’t seem to be commonly used. Sometimes if you’re dumping out several items at the same time, and potentially from separate files, it can be handy to identify the source of each one.

However I just noticed that the label seems to get applied to all complex data structures within the dumped variable. For example this code:

<cfset a.b.x = {a='one', b='two', c='three'}>
<cfset a.b.y = [1,2,3]>
<cfset a.b.z = 7>
<cfdump var="#a#" label="my struct">

Produces this output:

No big deal, just something I’d noticed. I guess ColdFusion recursively applies the label to all structures as it dumps them out.

« Previous PageNext Page »

Theme: Rubric. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.