Saturday, February 24, 2007

Dust StormSo I drifted into a nice nap today around 1 pm, with clear skies outside and high winds. I awoke about 3 pm to the smell of dust, as if someone were changing a vacuum cleaner bag nearby. I also noticed a hazy light behind the blinds. At first I didn't connect the two. I stretched, went upstairs to get a book and, still smelling dust, peered out my bedroom window. Dust was everywhere, a thick yellow-orange fog covering the ground, blowing in from the barren Texas panhandle. I'd never seen anything like it before.

It was eerie being in that light. I couldn't help but think of nuclear winter and the fragility of our climate. I think I'll be making a donation to the National Arbor Day Foundation.

Fortunately the dust has pretty much blown away by now. Here's what it looked like in McKinney, about 20 minutes from where I live, courtesy of WeatherBug's Instacam:

A crazy dust storm that blew through one Saturday afternoon.

Sunday, February 04, 2007

OrganicityFor many years, I rarely ate apples. They simply didn't taste good to me. It was only in the last couple of years that I began eating apples more frequently, and I no longer have an aversion to them. What changed? I never really thought about that question, and definitely didn't have an answer, until Brian's mother lent me the Organic Cook's Bible, by Jeff Cox.

In the opening lines of the book, Cox describes the best apple he ever tasted. It was a blackish red, somewhat rare variety of apple that he bought at a small market. Cox goes on to discuss the only apple variety most of us are familiar with:

The proliferation of the inferior Red Delicious is due to two primary marketing factors. First, the apples have deep red skins and consumer preference tests show that people associate a deep red apple with quality, even if, as with Red Delicious, there's precious little quality to the flavor. Second, they are called "delicious" even though they aren't.
As I read those lines, it dawned on me that for all these years, I had been avoiding not apples, but a single variety of apple, the variety which is usually the only one you can get. Then two years ago I moved next door to a Whole Foods, which has much more to offer than Red Delicious, and organic too. Thus my re-acquaintance with apples.

Here's a photo, by the way, of the type of apple that Cox had. Alas for "consumer preferences".

This story is not limited to apples. The food industry, like some Plato scared of variety, has long been on a quest to reduce food to these limited ideals. Red Delicious is "the" apple (or maybe Granny Smith). Black Beauty is "the" eggplant. White Button is "the" mushroom. And on throughout the food supply:
Scientists have recorded over 15,000 plants that have been used by human beings as food over the millennia, but there are only about 150 commercially important food crops worldwide these days. And in the large corporate food systems that provide foods to our supermarkets and big commercial stores, only a few of these 150 commodities are typically available to the consumer.
And as is the case with apples, the chosen variety is frequently the inferior one. Cox, former editor of Organic Gardening, introduces us to the other varieties of vegetables, fruits, nuts and grains throughout the book, and while perusing his in-depth descriptions, I was struck by how little I know about the food I eat.

For instance, there is a variety of eggplant that actually looks like a white egg. Avocado flowers are the only flowers which change their sex. Black canned olives are actually green unripe olives soaked in lye. Pineapple juice can eat your skin. These are some of the more odd and intriguing facts among all the information about varieties, seasons, growing tips, and best regions to grow what—knowledge that has been lost in our age of standardized food available year round. Quick: what type of food grows best in the area you live in?

I don't know either, but this book makes me want to find out.
Over centuries and sometimes millennia, local people had learned which crops and types of livestock thrived in their climate and on their soils. ...Cooking techniques and recipes were for centuries very region-specific, and over time cooks in those areas learned how to make the most palatable dishes from unique local products. ...The French call these site-specific flavors terroir, or soil, which is a succinct way to describe the phenomenon that each specific place on the earth will express itself in the taste of the food that grows there.
The food industry has been steadily trying to destroy terroir with inferior-tasting food, an arsenal of chemicals, and genetic-engineering. Terroir is the opposite of what most corporations are all about: standardization and monotony, also known as branding. That you can go from Beijing to Bangalore to Paris to New York, and in each place get Big Macs and Frappuccinos, is the corporate, anti-terroir wet dream.

Although the major food corporations have tried and will continue trying to water down organic food rules, it looks like the tide is turning somewhat with the growth of of the organic food movement in recent years. Cox has been involved in this movement since the beginning (in America), and the book is interspersed with 250 wonderful recipes that he's collected over the years, and with stories of the unique, delicious, and local food he's encountered in his travels across the country. Reading this book makes you hungry, but with a different sort of hunger. You want to stop at a rural fruit stand, you want to pick something in the wild, to find food at the right time and the right place—and savor those lucky moments which you can't get with conventional food. If you care about the environment and the food you eat, this book is definitely worth buying.

I must end with one last fact, this one about rabbits:
Buck rabbits are either screamers or fainters. That is, after they mate with a doe, they either scream or faint. Just a point of interest.

Some relevant links:

http://www.slowfoodusa.org/
http://www.oldwayspt.org/
http://www.treesofantiquity.com/
http://www.localharvest.org/
http://www.gourmetsleuths.com/

Map Your Travels, 2.0UPDATE: 07-15-2007 - Blogger made some more minor feed changes which broke this hack. This was a modification to the summary category feed, and specifically it was a change in the order of the links available per entry. Previously link entry number 1 pointed to a summary version of the post. Now link number 1 points to the comments.

To correct this, in the function storeFeed I had to modify this line:

var link = entry['link'][1].href;

to this:

var link = entry['link'][2].href;

UPDATE: 06-11-2007 - Blogger apparently made some minor changes to their feeds recently which changed the ordering of some feed items and broke this hack. Specifically, there's a function storeFeed which had the following lines:

if (i==0) {
var category = entry['category'][0].term;
var index = mapLevels.indexOf(category);
}

The index variable was returning a value of -1, meaning it did not exist. To get this to work again, I had to change the category to entry['category'][1].term. I have updated the code below.



Shortly before implementing the Travel Map hack, I heard that Blogger began offering JSON versions of their feeds. Blogger had long offered Atom feeds, but those could not be utilized without a feed reader or aggregator, requiring a set up with non-Blogger applications if you wanted to use your own feeds in your own blog.

JSON changes all of that, and being able to use my own Blogger feeds in my blog, the Travel Map hack can be vastly simplified and improved. I put it off for a while, but due to some odd behavior in the first version, I worked on and now unveil version 2 with AJAJ.

Microsoft Internet Explorer still can't handle this feature (v6 or v7), so the "places I've been" link below my profile remains disabled if you're using IE. But if you want to watch IE crash, here's a live link. And again, if anyone knows the nonstandard MS-HTML I need to use to prevent IE from crashing, let me know.

The way the posts need to be composed has changed slightly from version 1:

Post Titles

All post titles must consist of: higher-level post name, this-level post name, latitude, longitude, zoom level, and H S or M map type (Hybrid, Satellite, or Map).

All of these values must separated by commas, no spaces. Examples:

Map,world,35.704857,-6.926808,1,S
world,China,35.86166,104.195397,3,H
China,Great Wall,40.355595,116.009375,17,S
China,Wuhan,30.579997,114.269829,12,S
Wuhan,York Bar,30.589035,114.297032,18,S
How does one get the latitude and longitude? The easiest way is to go to Google Maps, find the place you're looking for, and click on "Link to this page." You'll see the page reload, and in the address bar, you'll see part that goes "&ll=" followed by two numbers:



This is the latitude and longitude, and you can copy them directly from there. Incidentally, the zoom level will be just before this, where it says "&z=".

For the world post, which is the introductory top-level post, the initial value in the title must be "Map", like so:
Map,world,35.704857,-6.926808,1,S

Post Labels

Each post should have two labels. Every post should have the label, atravelmap. Then, each post should have another label depending on what level it's on: countrymap, regionmap, citymap, or placemap. The atravelmap label is used to group all these posts together. The other labels are there to help with sorting the posts into the right hierarchy.

The CSS will prevent these labels from appearing in the labels widget.

Post Date

Before you publish the post, you need to backdate it. Usually I save the post as a draft first, then change the date and publish it. With the code I have above, the posts should be backdated to 1985 (I just arbitrarily chose this year). The code will prevent this year from appearing in the Blog Archive widget.

Also, the code will prevent any of the posts from appearing via the "Older" link. Note: if you don't have very many posts currently, you may need to modify your Blog Settings (Formatting) to only display a certain number of posts on your home page. This will prevent the travel posts, with their funky titles, from appearing on your homepage.

You will need to play with the months and days a bit to get them to show up alphabetically.

I also disable comments for my travel posts, and the code I have does not allow for comments to even be displayed for these posts, but that could be fairly easily changed.

Post Body

The post body has no special requirements. However, if you want a marker or markers to appear for a location, you must include a span with an id of "markers" in your post body. Within the span tags, you should include the latitude, longitude, and name of each marker. Each marker can appear on a separate line, like so:
<span id="markers">
39.930011,116.399975,Beijing
31.229999,121.470001,Shanghai
</span>Post text can begin here...
Note: This assumes the Settings -> Formatting -> Convert line breaks is set to Yes. In other words, when you hit Enter when composing a post, it will be replaced with a single <br /> tag in your blog. If you have this setting on No, then the markers should be entered as follows:

<span id="markers"><br />
39.930011,116.399975,Beijing<br />
31.229999,121.470001,Shanghai<br />
</span>Post text can begin here...

NEW! By request, you can now show routes, trails, or paths with some data included in your post body. For this functionality to work, you'll need to get a hex color, and two pieces of data from this Google utility. In particular, you will use this utility to draw your route, and then obtain the Encoded Polyline and the Encoded Levels that it generates.

In the body of your email, include this span:
<span id="routes">
#FF0000,10,BBBBBBB,gutyDu~oxTzFgI|DiFhE}FxEiGjFaHjEeG
#3333cc,5,BBBBBB,{avyDmcqxTzVYaJaIpMkS`G}JgMaE
</span>Post text can begin here...

You can have multiple routes, one route per line (no carriage returns in the middle of the route data!). The first bit of data will be your hex color, which of course will be the color of the line on the map. The second bit is the line width (I'm not sure what the ranges are). The third bit of data is the Encoded Levels that you get from the Google utility mentioned above, and the fourth bit of data is the Encoded Polyline.

Note: This assumes the Settings -> Formatting -> Convert line breaks is set to Yes. In other words, when you hit Enter when composing a post, it will be replaced with a single <br /> tag in your blog. If you have this setting on No, then the markers should be entered as follows:
<span id="routes"><br />
#FF0000,10,BBBBBBB,gutyDu~oxTzFgI|DiFhE}FxEiGjFaHjEeG<br />
#3333cc,5,BBBBBB,{avyDmcqxTzVYaJaIpMkS`G}JgMaE<br />
</span>Post text can begin here...

Also note that the Polylines are a little buggy. I noticed when I was experimenting with it that random markers would sometimes appear. You can see the one example (so far) on my map by clicking on China -> Wuhan -> Jianghan Road.

The code below has been updated to include this new functionality.

Here's how to add this functionality to your blog:

1. Go here to get a Google Maps API key for your blog. There's no limit on the number of URL's you can register for a key, so I'd highly recommend getting one for a test blog first.

2. Generate an animated loading graphic here, and download it to your machine.

3. Start a new post and upload the graphic you created in step 2. After it uploads, you'll see some HTML appear in your post. Copy the web address that is between the quotes where it says href="". Save this post as a draft (entitle it something like "Graphics"). The purpose of this post is only for allowing you to upload graphics, photos, etc for use on your blog, and should always remain in draft status.

4. In the Page Layout view, add three HTML/JavaScript widgets to your blog:
a. Map Control - put this in your sidebar. This widget will contain the links to the various map locations.
b. Google Map - put this one in the large main section, above the Blog Posts widget.
c. Map Link - put this wherever you want the link to your travel map to appear (probably somewhere near your profile widget).

5. Download your template, and open it in a text editor. Add the following to your style sheet between the tags: <b:skin><![CDATA[/* and ]]></b:skin> :

li#atravelmap, li#worldmap, li#countrymap, li#regionmap, li#citymap, li#placemap {
display:none;}

a.worldmap:link, a.countrymap:link, a.regionmap:link, a.citymap:link {
text-decoration:none; color:#3a80b4;}

#worlddiv, #countrydiv, #regiondiv, #citydiv {
margin-left: 5px;}

#countrydiv li, #regiondiv li, #citydiv li {
list-style-type:none; display:inline;}

#placediv ul {
margin-left:13px;}

#placediv li {
list-style-type: disc; text-align: left;}

#markers {
display:none;}

#routes {
display:none;}

6. Add the following scripts to the header element, between the tags: ]]></b:skin> and </head> :

<script type="text/javascript">
var priorEntry = "";
var count = 0;
var highlightCount = 0;

var mapLevels = new Array("worldmap","countrymap","regionmap","citymap","placemap");
var entryTitle = new Array();
var postFeedLink = new Array();
var postID = new Array();

function loadMapFeeds() {
priorEntry = "Map";
entryTitle.length = 0;
postFeedLink.length = 0;
postID.length = 0;
count = 1;
highlightCount = 0;

for (var i=0; i &lt; mapLevels.length; i++) {
document.getElementById("contentdiv").innerHTML = "<img alt='Loading...' src='link-to-your-animated-loading-gif' />";

var divID = mapLevels[i].replace(/map/,"div");
document.getElementById(divID).innerHTML = "";

if (document.getElementById("catFeed" + i)) {
var scriptid = document.getElementById("catFeed" + i);
scriptid.parentNode.removeChild(scriptid);
}

entryTitle[i] = new Array();
postFeedLink[i] = new Array();
postID[i] = new Array();

var feed_load = document.createElement('script');
var url = "/feeds/posts/summary/-/"+mapLevels[i]+"?alt=json-in-script&amp;callback=storeFeed&amp;max-results=200";
feed_load.src = url;
feed_load.type = "text/javascript";
feed_load.id = "catFeed" + i;
document.getElementsByTagName('head')[0].appendChild(feed_load);
}
}

function storeFeed(root) {
var feed = root.feed;

for (var i = 0; i &lt; feed.entry.length; i++) {
var entry = feed.entry[i];

if (i==0) {
var category = entry['category'][1].term;
var index = mapLevels.indexOf(category);
}

var title = entry.title.$t;
var link = entry['link'][2].href;
var post_id = entry.id.$t;

entryTitle[index].push(title);
postFeedLink[index].push(link);
postID[index].push(post_id);

if(i==(feed.entry.length-1)) {
count++
}
}

if (count==mapLevels.length) {
showTitles(0);
}
}

function showTitles(level) {
var html = ['&lt;ul&gt;'];
for (var i = 0; i &lt; entryTitle[level].length; i++) {
var splitTitle = entryTitle[level][i].split(",");
if (splitTitle[0]==priorEntry) {
var aposTitle = splitTitle[1].replace(/'/,"apostrophe");
var nextEntry = '\"' +aposTitle+ '\"';
var t = getType(splitTitle[5]);
var link = postFeedLink[level][i].replace(/summary/,"full");
var quoteLink = '\"' + link + '\"';
var splitPostID = postID[level][i].split("-");
quotePostID = '\"' +splitPostID[2]+ '\"';
var category = '\"' + mapLevels[level] + '\"';
if (mapLevels[level]=="placemap") {
html.push("<li><a href='javascript:void(0);' onclick='javascript:showContent(",quoteLink,"); map.clearOverlays(); map.setCenter(new GLatLng(",splitTitle[2],",",splitTitle[3],"),",splitTitle[4],",",t,")'>", splitTitle[1], "</a>", "</li>");
}
else {
html.push(" <li><a class='",mapLevels[level],"' id='",splitPostID[2],"' href='javascript:void(0);' onMouseOver = 'javascript:highlightmap(" ,quotePostID, ")' onMouseOut='javascript:unhighlightmap(" ,quotePostID, ")' onclick='javascript:showContent(",quoteLink,"); showNext(",nextEntry,",",category,",",quotePostID,"); map.clearOverlays(); map.setCenter(new GLatLng(",splitTitle[2],",",splitTitle[3],"),",splitTitle[4],",",t,")'>", splitTitle[1], "</a>", "</li> ");
}
}
}

var whatdiv = mapLevels[level].replace(/map/,"div");
document.getElementById(whatdiv).innerHTML = html.join("");
if (mapLevels[level]=="worldmap" &amp;&amp; count==mapLevels.length) {
showContent(link);
showNext(aposTitle,mapLevels[level],splitPostID[2]);
count = 0;
}
}

function showNext(nextEntry,category,thisPostID) {
nextEntry = nextEntry.replace(/apostrophe/,"\'");
priorEntry = nextEntry;

var allCategoryClass = getElementsByClass(category);
for(var y=0;y &lt; allCategoryClass.length;y++) {
allCategoryClass[y].style.backgroundColor="#efefef";
allCategoryClass[y].style.color="#387fb5";
}

document.getElementById(thisPostID).style.backgroundColor="#c0c0c0";
document.getElementById(thisPostID).style.color="#000000";
highlightCount++;

var index = mapLevels.indexOf(category);
for (i=index+1; i &lt; mapLevels.length; i++) {
showTitles(i);
}

}

function showContent(postFeedLink) {
document.getElementById("contentdiv").innerHTML = "<img alt='Loading...' src='link-to-your-animated-loading-gif' />";

var content_load=document.createElement('script');
var url=postFeedLink + "?alt=json-in-script&amp;callback=showfeedcontent";
content_load.src=url;
content_load.type="text/javascript";
document.getElementsByTagName('head')[0].appendChild(content_load);
}

function showfeedcontent(root) {
document.getElementById("contentdiv").innerHTML = "";

var entry = root.entry;
var html = ['&lt;p&gt;'];
var content = entry.content.$t;
html.push(content);
document.getElementById("contentdiv").innerHTML = html.join("");

if (document.getElementById("markers")) {
var markers = document.getElementById("markers").innerHTML;
markers = markers.replace(/&lt;br \/&gt;/g,"|");
markers = markers.replace(/&lt;br&gt;/g,"|");
markers = markers.split("|");
var markernum = markers.length;
for (i = 0; i &lt; markernum; i++) {
if (markers[i]!="") {
var onemarker = markers[i].split(",");
var description = onemarker[2]
var point = new GLatLng(onemarker[0],onemarker[1]);
var marker = createMarker(point,description);
map.addOverlay(marker);
}
}
}

if (document.getElementById("routes")) {
var routes = document.getElementById("routes").innerHTML;
routes = routes.replace(/<br \/>/g,"¦");
routes = routes.replace(/<br>/g,"¦");
routes = routes.split("¦");
var routenum = routes.length;
for (i = 0; i < routenum; i++) {
if (routes[i]!="") {
var oneroute = routes[i].split(",");
var encodedPolyline = new GPolyline.fromEncoded({
color: oneroute[0],
weight: oneroute[1],
points: oneroute[3],
levels: oneroute[2],
zoomFactor: 32,
numLevels: 4
});
map.addOverlay(encodedPolyline);
}
}
}
}

function highlightmap (a) {
if (document.getElementById(a).style.backgroundColor=="rgb(192, 192, 192)") {
highlightCount++;
}
else {
document.getElementById(a).style.backgroundColor="#c0c0c0";
document.getElementById(a).style.color="#000000";
highlightCount=0;
}
}

function unhighlightmap (a) {
if (highlightCount == 0) {
document.getElementById(a).style.backgroundColor="#efefef";
document.getElementById(a).style.color="#387fb5";
}
}

// Thanks to Mike at http://www.econym.demon.co.uk/ for his tutorial, which included this bit:
function createMarker(point,html) {
var marker = new GMarker(point);
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml(html);
});
return marker;
}

function getType (a) {
var typeparameter ="";
var maptype = a;
if (maptype == "H") {
typeparameter = "G_HYBRID_MAP"
}
else if (maptype == "S") {
typeparameter = "G_SATELLITE_MAP"
}
else if (maptype == "M") {
typeparameter = "G_NORMAL_MAP"
}
return typeparameter;
}

function delay(a,b) {
map.panTo(new GLatLng(a,b));
}

// Thanks to Dustin Diaz at http://www.dustindiaz.com/ for this great Javascript function
function getElementsByClass(searchClass,node,tag) {
var classElements = new Array();
if ( node == null )
node = document;
if ( tag == null )
tag = '*';
var els = node.getElementsByTagName(tag);
var elsLen = els.length;
var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
for (i = 0, j = 0; i &lt; elsLen; i++) {
if ( pattern.test(els[i].className) ) {
classElements[j] = els[i];
j++;
}
}
return classElements;
}
</script>


7. Modify the three widgets you added previously as follows:

a.

<b:widget id='HTMLa' locked='false' title='Map Controls' type='HTML'>
<b:includable id='main'>
Add this <b:if cond='data:blog.url == "http://your-blog-name.blogspot.com/search/label/atravelmap"'>
Remove this <!-- only display title if it's non-empty -->
Remove this <b:if cond='data:title != ""'>
Remove this <h2 class='title'><data:title/></h2>
Remove this </b:if>
<div class='widget-content'>
<data:content/>
</div>
<b:include name='quickedit'/>
</b:if>
</b:includable>
</b:widget>


b.

<b:widget id='HTMLb' locked='false' title='Google Map' type='HTML'>
<b:includable id='main'>
Add this <b:if cond='data:blog.url == "http://your-blog-name.blogspot.com/search/label/atravelmap"'>
Remove this <!-- only display title if it's non-empty -->
Remove this <b:if cond='data:title != ""'>
Remove this <h2 class='title'><data:title/></h2>
Remove this </b:if>
<div class='widget-content'>
<data:content/>
</div>
<b:include name='quickedit'/>
</b:if>
</b:includable>
</b:widget>


c.

<b:widget id='HTMLc' locked='false' title='Map Link' type='HTML'>
<b:includable id='main'>
Add this <b:if cond='data:blog.url == "http://your-blog-name.blogspot.com/search/label/atravelmap"'>
Remove this <!-- only display title if it's non-empty -->
Remove this <b:if cond='data:title != ""'>
Remove this <h2 class='title'><data:title/></h2>
Remove this </b:if>
<div class='widget-content'>
<data:content/>
</div>
<b:include name='quickedit'/>
</b:if>
</b:includable>
</b:widget>


8. Find the Blog Posts widget:

<b:widget id='Blog1' locked='false' title='Blog Posts' type='Blog'>

Then find the main includable, and the div with an id of "blog-posts":

<b:includable id='main' var='top'>
<div id='blog-posts'>

Directly below the div element, add the following:

<b:if cond='data:blog.url == "http://your-blog-name.blogspot.com/search/label/atravelmap"'>
<div id="contentdiv">
</div>
<b:else />

Just before the closing div tag for the "blog-posts" div, insert the closing if tag, like so:

</b:if>
</div>


9. Add the following conditional tags around the "nextprev" include, and the "feedLinks" include, like so:

<b:if cond='data:blog.url != "http://your-blog-name.blogspot.com/search/label/atravelmap"'>
<!-- navigation -->
<b:include name='nextprev'/>

<!-- feed links -->
<b:include name='feedLinks'/>
</b:if>


10. In the "nextprev" includable, find the olderPageUrl conditional statement, and modify the href attribute so it includes the bolded text:

<b:if cond='data:olderPageUrl'>
<a expr:href='data:olderPageUrl + "&amp;updated-min=2000-08-31T00%3A00%3A00-00%3A00"' expr:title='data:olderPageTitle' id='blog-pager-older-link'><data:olderPageTitle/></a>
</b:if>

11. Find the label widget:

<b:widget id='Label1' locked='false' title='Labels' type='Label'>

In the data:labels loop, modify the <li> element so it includes the bolded text:

<b:loop values='data:labels' var='label'>
<li expr:id='data:label.name'>
<b:if cond='data:blog.url == data:label.url'>
<data:label.name/>
<b:else/>
<a expr:href='data:label.url'><data:label.name/></a>
</b:if>
(<data:label.count/>)
</li>
</b:loop>


12. Find the blog archive widget:

<b:widget id='BlogArchive1' locked='false' title='Blog Archive' type='BlogArchive'>

Assuming you are using the hierarchy view for your archive, find the "interval" includable, and add the conditional tags as follows:

<b:includable id='interval' var='intervalData'>
<b:loop values='data:intervalData' var='i'>
<b:if cond='data:i.name != "1985"'>
<ul>
<li expr:class='"archivedate " + data:i.expclass'>
<b:include data='i' name='toggle'/>
<a class='post-count-link' expr:href='data:i.url'><data:i.name/></a>
(<span class='post-count'><data:i.post-count/></span>)
<b:if cond='data:i.data'>
<b:include data='i.data' name='interval'/>
</b:if>
<b:if cond='data:i.posts'>
<b:include data='i.posts' name='posts'/>
</b:if>
</li>
</ul>
</b:if>
</b:loop>
</b:includable>

If you're using the flat view or drop-down menu, I'm not sure how to easily block out an entire year.

13. Add the following to the very last widget on your template (for me, this is the Profile widget). This should be inside the main includable:

<b:includable id='main'>


<b:if cond='data:blog.url == "http://your-blog-name.blogspot.com/search/label/atravelmap"'>
<script type="text/javascript">
setTimeout("loadMapFeeds()",200);
</script>
</b:if>


14. Save the template changes, and upload the template to Blogger. Go to the Page Layout view, and add the following data to your HTML widgets:

a. Map Control

<a href="http://your-blog-name.blogspot.com/">back home</a>
<p>
<ul>
<li>
<div id="worlddiv">
</div>
</li>
<li><span class="travelsection">country:</span>
<div id="countrydiv">
</div>
</li>
<li><span class="travelsection">region:</span>
<div id="regiondiv">
</div>
</li>
<li><span class="travelsection">city:</span>
<div id="citydiv">
</div>
</li>
<li><span class="travelsection">place:</span>
<div id="placediv">


</div>
</li>
</ul>
</p>


b. Google Maps

<script src="http://maps.google.com/maps?file=api&v=2&key=YOUR-GOOGLE-MAP-KEY" type="text/javascript">
</script>

<div id="map" style="width: 100%; height: 400px"></div>

<noscript>JavaScript must be enabled for Google Maps. JavaScript is either disabled or not supported by your browser.
</noscript>

<script type="text/javascript">
if (GBrowserIsCompatible()) {
// Display the map, with some controls and set the initial location
var map = new GMap2(document.getElementById("map"));
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(35.704857,-6.926808),1,G_SATELLITE_MAP);
map.enableContinuousZoom();
}
else {
alert("The Google Maps API is not compatible with this browser");
}
</script>


c. Map Link

<!--[if IE]>
<script type="text/javascript">
function iealert() {
alert("Internet Explorer does not support this function. Get the better browser. Get Firefox at http://www.mozilla.com");
}
</script>
<p>
<a id="travellink" href="javascript:void(0);" onclick="javascript:iealert();">places I've been</a>
</p>
<![endif]-->

<![if !ie]>
<p>
<a id="travellink" href="http://your-blog-name.blogspot.com/search/label/atravelmap">places I've been</a>
</p>
<![endif]></![endif]></![if>


Now you're all set. There's room for improvement, I know, and I'm eventually hoping to add some more functionality. If you see anything strange, or anything that I missed, or if you see something that is needlessly complex, leave a comment and let me know.A much improved Blogger Beta hack utilizing AJAJ that integrates Google Maps with your blog, and allows you to show the locations of your travels.