feedback
Feb 21 2008

Implementing Map Mashups with Mapstraction

by John Dyer

image A few years ago, I made my first map mashup with Google Maps for Dallas Theological Seminary. It allows visitors to search for churches around the world where DTS alumni are serving. Recently, we decided to update the mashup with several features in mind:

  1. Larger map - 2 years ago we were using a 800px wide layout and now we can use a 1024px layout
  2. Use updated API - Google has changed APIs since then
  3. Implement other maps - Yahoo and Microsoft each have good points
  4. Use custom icons - we are not just showing churches now, but also schools and counselors

To handle all of this, especially the implementation of other multiple map engines, I chose to use mapstraction, a JavaScript layer which allows developers to program against a common API for all mapping engines. It turns these two proprietary mapping code blocks:

// Google maps specific code
var gmap = new GMap2(document.getElementById("map"));
map.addControl(new GMapTypeControl());
gmap.setCenter(new GLatLng(37.4419, -122.1419), 13);
var gmarker = new GMarker( new GLatLng(37.443, -122.166) );
gmap.addOverlay(gmarker);
// Microsoft Live maps specific code
mmap = new VEMap('map');
mmap.SetDashboardSize(VEDashboardSize.Normal);
mmap.LoadMap();
mmap.SetCenterAndZoom(new VELatLong(37.4419, -122.1419), 10);
var shape = new VEShape(VEShapeType.Pushpin, new VELatLong(37.443, -122.166));
map.AddShape(shape);

into this single common set of code:

// universal map API, just change 'google' to 'yahoo', 'microsoft', etc.
var mapstraction = new Mapstraction('map','google');
mapstraction.addControls({ pan: true, zoom: 'large', overview: false, scale: true, map_type: true });
mapstraction.setCenterAndZoom(new LatLonPoint(37.4419, -122.1419), 12);
var marker = new Marker(new LatLonPoint(37.443, -122.166));
mapstraction.addMarker(marker);

In addition to Microsoft, Yahoo, and Google maps, you also get free access to a 3D map called Freeearth which is an amazing implementation of a 3D globe map (like Google Earth) using Papervision3D.

Examples

Here are examples using all four mapping engines. The only unique code is the shadow on the icons under Google maps. Also, prototype (which is used throughout the site) is handling the AJAX calls.

image image

image image

Try it out

Links

Feb 14 2008

Data Portability Pack for BlogEngine.NET

by John Dyer

What it Does

This is an initial release of 3 extensions which will add the follow protocols to your BlogEngine.NET blog:

  • SIOC - Somewhat like RSS, but utilizes RDF to describe connections to  other sites and between users and posts (example).
  • APML - Creates an "attention profile" of your interests based on tags and categories. Each is given a value based on its frequency (example).
  • FOAF - A list of your friends, their websites, and a hashed version of their email for a unique key (example).

You can see examples of each of these by clicking on the links on the upper right of this blog. To learn more about data portability, see this post. The following links show this data in a browsable format:

How it Works

imageEach of these has a Handler, a Generator, and an Extension file. The extension files automatically add <meta> discovery files to your <head> tag.

Note: Currently, the FOAF information is stored in two different Extension files due to a limitation in BE.NET 1.3 (it cannot store both scalar and table data). One extension is for your personal information and the other is for your friends' data. BE 1.4 will allow these to be merged into one file.

Warning: BE.NET currently deletes extension data when you change *.cs files, so please backup your extension file when adding or changing extensions.

Installation and Usage

  1. Download Data Portability Pack for BlogEngine.NET
  2. Copy the *.cs files into your /App_Code/Extensions folder (you can also create a sub-directory within that folder)
  3. Add the following to your web.config file
    	<add verb="*" path="sioc.axd" type="BlogEngine.DataPortability.SiocHandler, App_Code" validate="false"/>
    	<add verb="*" path="foaf.axd" type="BlogEngine.DataPortability.FoafHandler, App_Code" validate="false"/>
    	<add verb="*" path="apml.axd" type="BlogEngine.DataPortability.ApmlHandler, App_Code" validate="false"/>	
    	
  4. Go to your Admin->Extensions page and you should see 4 extensions prefixed with "DP_". The FoafFriends and MyProfile extensions need data entered, the other ones you can just leave as their defaults.
    image
  5. Optionally, you can add links to each of these files (as I have on the upper right)

Future Work

  • Merge FOAF extensions for BE 1.4
  • Possibly store FOAF data in a separate file rather than as Extension data
  • Add additional settings to APML such as parsing blog roll
  • If you also add OpenID support to your blog, then you will have everything that is currently on the data portability standards list.

kick it on DotNetKicks.com

Feb 8 2008

SIOC implementation for BlogEngine.NET

by John Dyer

Update: This is now part of the Data Portability Pack for BlogEngine.NET

A major feature of BlogEngine.NET is that it supports a lot of open standards. Keeping with this, I've setup an initial implementation of SIOC for BlogEngine.NET. SIOC (Semantically-Interconnected Online Communities) is an extension of RDF which goes beyond RSS in that it describes not only the content of a website, but the connections between site content, users on the site, and another websites. While RSS has one big document for recent content, SIOC splits up its data into (1) a site profile, (2) profiles for authors, (3) profiles for posts, and (4) profiles for comments. Each of these not only lists the author's name, but also includes FOAF (Friend of a Friend) data to help identify users across the Internet via a hashed email address. If all sites were SIOC/FOAF enabled, you could theoretically search an aggregator site (like Technorati if it supported SIOC) for all posts and comments by a given user within a set of blogs, forums, or other websites. For more information on this, see my post on Data Portability standards.

Site Profile

To get a feel for the data, here's what the site profile looks like (note: I've tried to match the Word Press SIOC plugin URL conventions as much as possible)
http://johndyer.name/sioc.axd?sioc_type=site

<rdf:RDF>
<!-- users -->
<sioc:Usergroup rdf:about="http://localhost/johndyer/sioc.axd?sioc_type=site#authors"> <dc:title>Authors at "John Dyer"</dc:title> <sioc:has_member> <sioc:User rdf:about="http://localhost/johndyer/author/John+Dyer.aspx" rdfs:label="John Dyer"> <sioc:see_also rdf:resource="http://localhost/johndyer/sioc.axd?sioc_type=user&amp;sioc_id=John+Dyer" /> </sioc:User> </sioc:has_member> </sioc:Usergroup>
<!-- site info -->
<sioc:Site rdf:about="http://johndyer.name/"> <dc:title>John Dyer</dc:title> <dc:description>ASP.NET, Flash, and JavaScript from FreeTextBox and Dallas Seminary</dc:description> <sioc:link>http://johndyer.name/</sioc:link> <sioc:host_of>http://johndyer.name/sioc.axd?sioc_type=site#webblog</sioc:host_of> <sioc:has_group>http://johndyer.name/sioc.axd?sioc_type=site#authors</sioc:has_group>
</sioc:Site>
<!-- blog info, posts--> <sioc:Forum rdf:about="http://johndyer.name/sioc.axd?sioc_type=site#webblog"> <sioc:name>John Dyer</sioc:name> <sioc:link rdf:resource="http://johndyer.name/sioc.axd?sioc_type=site#webblog" /> <sioc:container_of> <sioc:Post rdf:about="http://johndyer.name/post/2008/02/BlogEngineNET-Extension-Flash-Video-Player.aspx" dc:title="BlogEngine.NET Extension: Flash Video Player"> <rdfs:seeAlso rdf:resource="http://johndyer.name/sioc.axd?sioc_type=post&amp;sioc_id=06af08e0-c4eb-421c-9e18-b618358d33ca" /> </sioc:Post> </sioc:container_of> </sioc:Forum> </rdf:RDF>

This describes (1) the users on the site (sioc:Usergroup) which would be blog authors, (2) the site in general (sioc:Site), and (3) and displays the content (sioc:Forum). Each of these has links to other SIOC documents for the user and then for the posts.

Post Profile

Here's what a post looks like:
http://johndyer.name/sioc.axd?sioc_type=post&sioc_id=612564cd-3cfa-42b5-92e9-44beb52f7cd5

<?xml version="1.0" encoding="utf-8"?>
<rdf:RDF xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:rss="http://purl.org/rss/1.0/" xmlns:admin="http://webns.net/mvcb/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content" xmlns:sioc="http://rdfs.org/sioc/ns#">
  <foaf:Document rdf:about="http://johndyer.name/">
    <dc:title>SIOC post profile for "John Dyer"</dc:title>
    <dc:description>A SIOC profile describes the structure and contents of a weblog in a machine readable form. For more information please refer to http://sioc-project.org/.</dc:description>
    <foaf:primaryTopic>http://johndyer.name/post/2008/02/Website-Break-Coke-vs-Diet-Coke-vs-Coke-Zero.aspx</foaf:primaryTopic>
    <admin:generatorAgent>BlogEngine.NET SIOC Generator (1.0) by John Dyer</admin:generatorAgent>
  </foaf:Document>
<!-- post data -->
<sioc:Post rdf:about="http://johndyer.name/post/2008/02/Website-Break-Coke-vs-Diet-Coke-vs-Coke-Zero.aspx"> <sioc:link rdf:resource="http://johndyer.name/post/2008/02/Website-Break-Coke-vs-Diet-Coke-vs-Coke-Zero.aspx" /> <sioc:has_container rdf:resource="http://johndyer.name/sioc.axd?sioc_type=site#webblog" /> <dc:title>Website Break: Coke vs. Diet Coke vs. Coke Zero</dc:title> <!-- post author -->
<sioc:has_creator> <sioc:User rdf:about="http://johndyer.name/author/John+Dyer.aspx"> <rdfs:seeAlso rdf:resource="http://johndyer.name/sioc.axd?sioc_type=user&amp;sioc_id=John+Dyer" /> </sioc:User>
</sioc:has_creator> <foaf:maker> <foaf:Person rdf:about="http://johndyer.name/author/John+Dyer.aspx" foaf:name="John Dyer"> <foaf:mbox_sha1sum>3eb435778fafc3efde35fba2ca731c6d3234178f</foaf:mbox_sha1sum> <foaf:homepage rdf:resource="http://johndyer.name/" /> <rdfs:seeAlso rdf:resource="http://johndyer.name/sioc.axd?sioc_type=user&amp;sioc_id=John+Dyer" /> </foaf:Person> </foaf:maker>
<dcterms:created>2/1/2008 4:40:53 PM</dcterms:created> <sioc:content> Today, we decided to take a break from web development and do something truly important: a taste test. Tim, Adam, Brian, and I wanted to see if we could identify Coke, Diet Coke, and Coke Zero in a blind test. We each had three cups that another team member had setup. We tasted each drink and tried to match the drink with the cup and also mark our favorite. Tim is the narrator and then the participants from left to right are: John (me), Adam, Tim, and Brian. </sioc:content> <content:encoded>&lt;p&gt;Today, we decided to take a break from web development and do something truly important: a taste test. Tim, Adam, Brian, and I wanted to see if we could identify Coke, Diet Coke, and Coke Zero in a blind test. We each had three cups that another team member had setup. We tasted each drink and tried to match the drink with the cup and also mark our favorite. Tim is the narrator and then the participants from left to right are: John (me), Adam, Tim, and Brian.&lt;/p&gt;</content:encoded> <!-- categories and tags -->
<sioc:topic rdfs:label="Off Topic" rdf:resource="http://johndyer.name//category/Off Topic.aspx" /> <sioc:topic rdfs:label="challenge" rdf:resource="http://johndyer.name//?tag=/challenge" /> <sioc:topic rdfs:label="soda" rdf:resource="http://johndyer.name//?tag=/soda" />
<!-- comments --> <sioc:has_reply> <sioc:Post rdf:about="http://johndyer.name/post/2008/02/Website-Break-Coke-vs-Diet-Coke-vs-Coke-Zero.aspx#id_a82699f9-77e2-460d-b3b1-d1d470180df9"> <rdfs:seeAlso rdf:resource="http://johndyer.name/sioc.axd?sioc_type=comment&amp;sioc_id=a82699f9-77e2-460d-b3b1-d1d470180df9" /> </sioc:Post> </sioc:has_reply>
<!-- outbound links --> <sioc:links_to rdf:resource="http://www.cokezero.com/" rdfs:label="Coke Zero" /> </sioc:Post> </rdf:RDF>

This one also has a "document" description (which I left out on the site profile) and then has information about the post including its author (both sioc:has_creator and foaf:maker which has my email as a SHA1 hash), content (sioc:content and content:encoded), categories (sioc:topic), outbound links (sioc:links_to), and then links to the comments for the post (sioc:has_reply)

Download and Installation

  1. Download BlogEngine.NET SIOC extension
  2. Copy the three files into the \App_Code\Sioc\ directory
  3. Add the following line to your web.config
    <add verb="*" path="sioc.axd" type="SIOC.SiocHandler, App_Code" validate="false"/>

Update: This is now part of the Data Portability Pack

What's Next?

  1. This extension will add a <link> tag to your header, but you view it directly at: http://yoursite.com/sioc.axd
  2. Explore the SIOC file at:  http://sparql.captsolo.net/browser/browser.py?url=http%3A%2F%2Fjohndyer.name%2Fsioc.axd
  3. An SIOC explorer is also available here which allows you to search and sort the data from among several sites: http://www.activerdf.org/sioc/
Feb 5 2008

Introduction to DataPortability and the state of its standards

by John Dyer

imageSince November 2007, the DataPortability discussion has been big news. The following post is an overview of the underlying ideas of "data portability" as well as the status of the proposed technologies which will enable it.

What is Data Portability?

The idea behind "data portability" is that website visitors should be able to control the data that a site has about them. It's a philosophical ideal that harkens back to the early days of the Internet before big businesses got into the game, and the Internet was thought to be a place of independence and freedom. Today, Gmail has all my email, Facebook has my friends, flickr my photos, Amazon my book and music purchases, and so on. DataPortability is a work group which is trying to urge these web companies to allow its users to export all of their data and be able to import into another site at will. Over the past month, representatives from big players like Microsoft, Google, and Facebook have joined DataPortability to help create standards for data transmission.

Here's a video explanation:

 


DataPortability - Connect, Control, Share, Remix from Smashcut Media on Vimeo.

 

What will I hopefully be able to do with Data Portability?

Though you can't do anything yet since "data portability" is just an idea right now, here are two possible scenarios:

Transferring friends and interests between sites. Facebook has data on who my "friends" are and information about things they like; Amazon has information on book and music I like based on what I've purchased and clicked on over the years; Pandora has information on what music I like, and so on. If one of my musician friends joined another social network like Bebo and I wanted to follow him, "data portability" would allow me to compile my interests and friends from Facebook, Amazon, and Pandora together and import that data into Bebo so I didn't have to start over there. It would already know what I like and who my friends are.

Collating my online activities. Much of my life has either "happened" on the web (blog posts, facebook messages, flickr photos, etc.) or I have left a record of real world events on the Internet. It would be good for me to be able to get all of this data and store it for my own use. Today I can't do this, but if all those sites were enabled with "data portability," I could theoretically pull out my photos from flickr, tickets from American Airlines, blog posts, emails, reviews at Trip Advisor, etc. and put together a timeline of my last vacation.

What possible problems are there with Data Portability?

"Data portabilty" sounds great in theory, but there are some problems that have to be overcome before it can really happen. These "problems" are not deal-breakers, just issues that the DataPortability workgroup is attempting to solve, and things users ought to think through before they immediately adopt such technology.

Identity verification. Probably the biggest technical hurdle is in the area of "identity management." If your list of friends has more than one person named "John Smith" or a friend with just a screen name like "JohnMayerLover556," then it will be difficult to import these into another site, especially if that site has has 10 more users named "John Smith." Websites usually assign a number to keep track of each user (a unique ID), but these cannot be shared among sites since they often overlap. Some standards propose using an email address as a unique ID, but people generally don't want their email address openly shared because of SPAM. One proposed standard (FOAF, see below) proposes using hashing the email address, but currently many sites don't allow email to be exported (such as Facebook). Also, since this information is being exported from a site, it is then made more public. This will require that "friends" can be verified in both directions since someone could merely copy the unique ID into their friends list.

Business value. There is some question as to why big websites would want to do "data portability" even if they've already joined the DataPortability workgroup. Most introductions to "data portability" usually use Amazon as an example, but interestingly Amazon has not yet joined. They have worked hard to build a great store, and they have collected a lot of data over a long period of time that they are not likely to want to give up to every new site that pops up. Similarly, Facebook's targeted advertisement platform is built on the interests that users enter into the site. This is an important part of their business model, and not something they are likely to give up unless there is a good business reason to do so. I don't think that Google, Microsoft, and Facebook joined DataPortability merely of good will and adherence to philosophical ideals of freedom, but because they believe they can make money doing so.

Security. As with "identity management" the overall security of publicly posting a lot of data about oneself could pose problems. For example, if I post all my interests, all my website associations, all my personal relationships in accessible XML files, then "identity" theft could be a genuine possibility. If someone can do damage with just a name, address, and social security number, imagine what they could do with data that allows them to mimic your lifestyle.

What technologies will hopefully enable Data Portability?

So "data portability" has awesome potential and some problems to work through. Another issue is what "standards" should be used to transfer this data. Long before the DataPortability workgroup was formed, several formats were proposed to handle this kind of information. Here is a summary of four of the most important ones:

  • image OpenID - Instead of having separate usernames and passwords for each site you visit, OpenID allows you to have one login across the internet that you control through a URL. For example, I could have openid.johndyer.name be my OpenID. If I go to a site that supports OpenID, I would not enter a username and password at that site, but just my OpenID (openid.johndyer.name). The site would send me to openid.johndyer.name where login and then verify that I wanted to return to the sending site. This way, I control the username and password and I can use it anywhere.
  • image SIOC (Semantically-Interlinked Online Communities) - SIOC's goal is to connect websites and content on those sites together. For example, it should be able to help identify blog posts, Amazon book reviews, blog comments, and forum posts made by the same person. Also, it should be able to semantically connect websites and blogs based on their tags and content. Right now, plugins exist for popular web applications (such as WordPress and phpBB), but there are very few applications which can actually do much with the data.
  • imageFOAF (Friend of a Friend) - While SIOC is about websites and content, FOAF is more about people and relationships. The idea is to be able to represent "friend" lists in a standard way. Obviously this introduces security questions (do I really want my friends on Facebook importing my data into xanga?), but some have already been addressed. FOAF proposes using either OpenID or a hashed email as a unique ID. In addition to relationships, FOAF can also describes activities people do through calendars, photos, blogs, etc. (working example: Facebook FOAF exporter app)
  • image APML (Attention Profile Markup Language) - APML is the proposed standard for cataloging "interest." The idea is to take all of the things you do on the web (uploading photos, blog posting, music and book purchases, etc.) and organize the related subjects and topics into one standardized document of your interests. If you found a new music store or website, and you wanted to see if it had things you like, you could upload your APML document, and it would filter its data to only show things of interest to you. (see: http://www.engagd.com/ for a working example)

There are also additional proposals for relationships (XFN), personal details (hCard), and identity management (Yarid) which have some overlap with the standards above. Also, OMPL is a standard for collecting lists such as the RSS feeds. Here is the full list of proposed standards.

What does it all mean and what can I do today?

Since there are very few real world uses of these technologies, "data portability" is only an idea at this point. Right now, there are no sites listed as "DP Enabled" This is mostly because "DP" hasn't been fully defined yet which shows us how early in the game this all is. OpenID perhaps has the greatest number of sites which support it, though some sites are merely offering their own login as an OpenID (for example, Yahoo offers openid.yahoo.com/youryahooid as an OpenID URL). AMPL, FOAF, and SIOC are currently not supported by any major sites, and they may not for some time unless a unique ID can be reliably used. Also, it seems that the current standards can't really handle all that the entire "connect, control, share, remix" vision, so a lot of work will probably need to be done. Hopefully it will go more smoothly than HTML5 and ES4 development.

Interestingly, the idea behind "data portability" is a lot like the early 90s before the Internet was widely available and people were on closed networks like AOL and Compuserve. They could only send email to people on the same network, but when Netscape came on the scene, access became universal, email and HTML became standard, and it changed everything. Today users are on different networks (MySpace, Facebook, xanga, etc.) with no way to connect. Hopefully, "data portability" will be able to change all that.

Links:

Feb 4 2008

BlogEngine.NET Extension: Flash Video Player

by John Dyer

Last week, I posted a flash video using flvplayer extension from betaparticle for BlogEngine.NET. I wanted to make some adjustments to the extension and I ended up completely rewriting it.

Updates/improvements:

  • Plays FLV or MP4.
  • All properties are available in the BlogEngine.NET extension manager so you don't have to touch the code to change settings.
  • The size of the player will automatically make room for the controls at the bottom (20px)
  • Uses SWFObject for flash replacement. This allow graceful degradation for those without Flash including mobile users. (I'll upgrade it to SWFObject 2.0 when it's released)
  • Enables Fullscreen playback.
  • Shows an initial image at startup named the same as the flv (myvideo.flv and myvideo.jpg). This way the video is not black at startup.
  • Optionally, instead of SWFObject, full <object><embed> formatting can be used.

Credits

Uses

Installation & Usage

  1. Download the file and unzip: Flash Video Player extension for BlogEngine.NET
  2. Copy FlashVideoPlayer.cs to /App_Code/Extensions/
  3. Copy the flashvideo folder to the root of your application (this can be customized in the settings)
  4. Add videos (myvideo.flv or myvideo.mp4) and images (myvideo.jpg) to the flashvideo folder.
  5. To use, just add [flv:myvideo.flv] anywhere in your post.

Example

oregon
This video requires Adobe Flash player

Download:

Feb 1 2008

Website Break: Coke vs. Diet Coke vs. Coke Zero

by John Dyer

Today, we decided to take a break from web development and do something truly important: a taste test. Tim, Adam, Brian, and I wanted to see if we could identify Coke, Diet Coke, and Coke Zero in a blind test. We each had three cups that another team member had setup. We tasted each drink and tried to match the drink with the cup and also mark our favorite. Tim is the narrator and then the participants from left to right are: John (me), Adam, Tim, and Brian.

coke_challenge
This video requires Adobe Flash player

Results: Adam, Brian, and I all correctly identified the three flavors of Coke. Adam and I choose Coke Zero as the best, while Brian favored Coke Classic. The most interesting result was that Tim thought Coke Zero was Coke Classic and he also thought it was the best tasting. So, Coke Zero is our big winner.

coke_challenge

Please post your workplace challenge!