Important:
This is retired content. This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This content may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.
4/7/2010

Jim Wilson, JW Hedgehog, Inc.

May 2008

Summary

In this article, Jim Wilson explains why ASP.NET sites that work with Microsoft® Internet Explorer® Mobile on Microsoft Windows Mobile® 5.0 may not render correctly when accessed from Internet Explorer Mobile on Windows Mobile 6 and Windows Mobile 6.1; he then demonstrates how to overcome this issue through the addition of a custom browser definition file.

Download WM6PlusBrowser.zip from the Microsoft Download Center.

Applies To

ASP.NET

Microsoft Visual Studio® 2008

Visual Studio 2005

Microsoft Windows Mobile 6 Professional

Microsoft Windows Mobile 6 Standard

Microsoft Windows Mobile 6 Classic

Microsoft Windows Mobile 6.1 Professional

Microsoft Windows Mobile 6.1 Standard

Microsoft Windows Mobile 6.1 Classic

Introduction

Windows Mobile 6 and Windows Mobile 6.1 provide a substantially improved Internet Explorer Mobile browser than that on earlier versions of Windows Mobile. What you may find surprising is that ASP.NET sites that work perfectly with Windows Mobile 5.0 devices sometimes seem to not work as well with Windows Mobile 6 and Windows Mobile 6.1 devices, which is not what one expects from an "improved" browser.

The problem stems from the fact that ASP.NET sites created with Visual Studio 2008 and earlier do not fully recognize Internet Explorer Mobile on Windows Mobile 6 and Windows Mobile 6.1 devices. Because ASP.NET doesn't recognize Internet Explorer Mobile on these devices, the capability properties that ASP.NET stores in the HTTP request's HttpBrowserCapabilitiesinstance are not set correctly. With the capability properties incorrectly set, the Internet Explorer Mobile browser on Windows Mobile 6 and Windows Mobile 6.1 appears to ASP.NET to have extremely limited feature support. The biggest impact of this being the case is that ASP.NET renders the page content as if the Internet Explorer Mobile browser has no client-side scripting capability. As you probably know, client-side scripting is key to ASP.NET rendering rich and responsive content.

This paper provides an explanation of the changes in Internet Explorer Mobile on Windows Mobile 6 and Windows Mobile 6.1 that create this situation and provides an easy-to-implement solution that will have your ASP.NET sites properly recognizing Internet Explorer Mobile on Windows Mobile 6 and Windows Mobile 6.1 devices. With these simple changes, ASP.NET content will work as well or better on Windows Mobile 6 and Windows Mobile 6.1 than on earlier versions of Windows Mobile.

What We Have

As is the case in most Web server scenarios, ASP.NET relies on the user agent header the browser sends as part of the server request to identify the browser making the request. Although the user agent header doesn't specify the supported behaviors of the client browser, it provides identification information that can be used to look up the client browser's supported behaviors.

Note:
Although this discussion focuses on using the user agent header to determine client browser capabilities, client browsers also send additional HTTP headers that can be useful in identifying specific browser capabilities beyond those that can be determined by using the user agent header alone. Examples of using these additional headers appear later in this article.

Windows Mobile 5.0 User Agent

In the case of a Windows Mobile 5.0 Pocket PC, the user agent header looks similar to the following:

Copy Code
Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; PPC; 240x320)

As you may recall, in ASP.NET the browser capabilities corresponding to the client browser headers are defined in a series of files with a .browserextension. The standard browser definitions are stored in %SystemRoot%\Microsoft.NET\Framework\v2.0.50727\CONFIG\Browsers. All browsers start with the capability properties defined in the default.browserfile with Mozilla-style browsers (includes Internet Explorer, Internet Explorer Mobile, and many other browsers) having their capability properties further defined by the mozilla.browserfile. ASP.NET goes on to determine each browser's capability properties more precisely based on the contents of the other browser files. In the case of Internet Explorer Mobile, most of the capability properties are determined using the contents of the pie.browserand gateway.browserfiles.

Note:
In earlier versions of Windows Mobile, Internet Explorer Mobile was known as Pocket Internet Explorer, which is why the Internet Explorer Mobile capability definitions are stored in a file named pie.browser.

Basically, the browser definitions files contain a series of <browser>sections with each browser section containing an <identification>section and a <capabilities>section. The <identification>section contains regular expressions that are used to identify user agent and other header values sent by the client; the corresponding <capabilities>section defines the HttpBrowserCapabilitiesproperties for clients whose headers match those regular expressions in the <identification>section. For the most part, determining the capability properties for a particular browser is pretty simple; if the browser header matches the regular expression in the <identification>section, the capability properties are set to the values defined in the <capabilities>section.

Note:
The above description is a simplification of the overall browser definition schema. For more information, see the Browser Definition Schema documentation in the MSDN® Library.

For a Windows Mobile 5.0 Pocket PC, there are three browser entries in the pie.browserfile that collectively define the Internet Explorer Mobile capability properties. The first section is the WinCEbrowser section.

Copy Code
<browser id="WinCE" parentID="Mozilla">
	<identification>
		<userAgent match="^Mozilla/\S* \(compatible; MSIE
(?'majorVersion'\d*)(?'minorVersion'\.\d*);\D* Windows
CE(;(?'deviceID' \D\w*))?(;
(?'screenWidth'\d+)x(?'screenHeight'\d+))?" />
	</identification>
	<capabilities>
		...
	</capabilities>
</browser>

This browser section sets 26 capabilities. I've omitted the specific capability settings for brevity; you can find the full list in the pie.browserfile. Notice that in addition to providing a match for the user agent value, the regular expression in the <identification>section stores five variable values which are used to set the capability properties as shown in table 1.

Table 1. Internet Explorer Mobile capabilities defined by WinCE browser section for Windows Mobile 5.0

Variable HttpBrowserCapabilities Property Value

majorVersion

majorVersion

4

minorVersion

minorVersion

01

deviceID

deviceID

PPC

screenWidth

screenPixelsWidth

240

screehHeight

screenPixelsHeight

320

The next browser entry affecting Windows Mobile 5.0 Internet Explorer Mobile browser capabilities is PIE4.

Copy Code
<browser id="PIE4" parentID="WinCE">
	<identification>
		<userAgent match="MSIE 4(\.\d*)" />
	</identification>
	<capabilities>
		...
	</capabilities>
</browser>

As you can see, this browser section sets the capability properties due to the presence of the Internet Explorer 4 (MSIE 4) compatibility entry in the user agent. This section sets 37 more capabilities.

The last section affecting Internet Explorer Mobile on Windows Mobile 5.0 devices is the PIE4PPCsection.

Copy Code
<browser id="PIE4PPC" parentID="PIE4">
	<identification>
		<userAgent match="PPC(;
(?'screenWidth'\d+)x(?'screenHeight'\d+))?" />
	</identification>
	<capabilities>
		...
	</capabilities>

Based on the fact that the client device is a Pocket PC-style device, this section sets another 27 capabilities; however, two of those capabilities, screenPixelHeightand screenPixelWidthwere previously set in the WinCEsection. Collectively, the PIE4PPC, PIEPPC, and WinCEsections define the capability properties specific to Internet Explorer Mobile on Windows Mobile 5.0 device.

Note:
As mentioned earlier in this article, some capability properties are also set in the gateway.browserfile. The specific capability properties set in the gateway.browserfile are outside the scope of this article because they are not affected by the changes to Internet Explorer Mobile on Windows Mobile 6 and Windows Mobile 6.1. The reader is encouraged to explore the contents of the gateway.browserfile to gain an understanding of the file's affect on the capability properties.

Windows Mobile 6 User Agent

As you can see, the capability definitions for Internet Explorer Mobile are tied very closely to the contents and structure of the user agent string; this is true for most browsers. Such a close tie to the structure of a specific user agent format can make the process of setting capability properties very sensitive, causing even minor changes to the user agent to negatively affect the process. This is exactly what happened with Internet Explorer Mobile on Windows Mobile 6 and Windows Mobile 6.1.

In Windows Mobile 6 the decision was made to move away from putting the specific device type in the user agent and instead identify the browser type and version number. This makes sense for a couple of reasons. First the device type and screen size is available in the ua-deviceheader, which makes having the values in the user agent redundant. The other issue is that including the specific browser type and browser version number allows for better page specialization as both server-side code and client-side script can more precisely target specific Internet Explorer Mobile versions.

The user agent value sent by Internet Explorer Mobile on a Windows Mobile 6 device looks similar to the following

Copy Code
Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 6.12)

On Windows Mobile 6.1 devices, the format is the same; the only difference is a higher Internet Explorer Mobile version number as shown in the following.

Copy Code
Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 7.11)

The Windows Mobile 6 and Windows Mobile 6.1 Internet Explorer Mobile user agent doesn't appear extremely different from that of Internet Explorer Mobile on Windows Mobile 5.0 but the differences are significant enough to have a dramatic effect.

The Windows Mobile 6 and Windows Mobile 6.1 Internet Explorer Mobile user agent values match the WinCEbrowser section's regular expression. By matching the WinCEbrowser's section, the 26 capability properties defined in that section are set for the browser but those capability properties that are derived from variables in the user agent are not necessarily set to meaningful values as shown in table 2.

Table 2. Internet Explorer Mobile capabilities defined by WinCE browser section for Windows Mobile 6

Variable HttpBrowserCapabilities Property Value

majorVersion

majorVersion

6

minorVersion

minorVersion

0

deviceID

deviceID

IEMobile

screenWidth

screenPixelsWidth

7

screehHeight

screenPixelsHeight

11

As you can see by the values in table 2, some of the capability properties set by this section are problematic. One issue, although minor, is that the browser version isn't being correctly captured; the user agent indicates an Internet Explorer Mobile version of 7.11 but the version information in the capability properties is set to the less-descriptive Internet Explorer compatible version of 6.0. This version number problem is just the beginning. Notice that the deviceIDthat is expected to be either Pocket PCor Smartphoneis set to a non-existent device type of IEMobile. Worst of all, the screenPixelsWidthand screenPixelsHeightproperties are incorrectly set to an unusable small size of 7 pixelshigh by 11 pixelswide.

The other two browser sections that set the Windows Mobile 5.0 Internet Explorer Mobile capability properties, PIE4and PIE4PPC, are not applied for Internet Explorer Mobile on Windows Mobile 6 because they require the presence of MSIE 4and PPCin the user agent respectively. If you read through the various browser sections in pie.browserand other *.browserfiles, you'll find that no browser section with a parentIDof WinCEmatches the updated user agent value. The result is that ASP.NET is aware of only a very limited set of capabilities for Internet Explorer Mobile on Windows Mobile 6 and Windows Mobile 6.1; as shown in table 2, of the few capability properties that are set, some are incorrect.

Understanding these issues, you can see why many ASP.NET sites that work well with Internet Explorer Mobile on Windows Mobile 5.0 and previous versions do not work as well when browsed to using Internet Explorer Mobile on Windows Mobile 6 and Windows Mobile 6.1.

What We Need

To properly support Windows Mobile 6 and Windows Mobile 6.1 Internet Explorer Mobile clients on your ASP.NET site, you need to provide additional browser sections that will set the capability properties correctly. At the time of this writing, Microsoft does not have a browser definition available that sets the capabilities correctly for Internet Explorer Mobile on Windows Mobile 6 and Windows Mobile 6.1.

Defining the Windows Mobile 6 and Windows Mobile 6.1 Capabilities

To fill this gap, I've defined the WM6Plus.browserbrowser capabilities file that is included in the download for this article. The WM6Plus.browserfile defines the Internet Explorer Mobile capabilities for Windows Mobile 6 and Windows Mobile 6.1. I created the WM6Plus.browserfile through a combination of research and experimentation; in addition to simply spending too much time doing browser capability tests, the 6.12 Browser Standards list , the Summary of Mobile Browser Features sections of MSDN were key to creating this browser capabilities file.

Note:
To my knowledge, the capabilities defined in the file are correct but no one has performed a formal review of the capability definitions. You should review the file for accuracy and confirm that the file provides the desired functionality in your specific usage scenario.

The WM6Plus.browserfile contains two browser sections and three gateway sections. The first browser section, IEMobile, handles setting the majority of Windows Mobile 6 and Windows Mobile 6.1 Internet Explorer Mobile capabilities.

Copy Code
<browser id="IEMobile" parentID="WinCE">
	<identification>
		<userAgent match="IEMobile (?'version'\d+\.\d+)" />
	</identification>
	<capture>
		<userAgent match="MSIE (?'msieMajorVersion'\d+)" />
		<header name="UA-PIXELS"
match="(?'screenWidth'\d+)x(?'screenHeight'\d+)" />
	</capture>
	<capabilities>
		<capability name="breaksOnInlineElements"			 
  value="false" /> 		
		<capability name="browser"						
  value="IEMobile" />
		<capability name="cdf"							
  value="true" />
		<capability name="defaultScreenPixelsHeight"		
  value="${screenHeight}" />
		<capability name="defaultScreenPixelsWidth"			 
  value="${screenWidth}" />
		<capability name="ecmascriptversion"				
  value="1.2" />
		<capability name="javaapplets"					
  value="true" />
		<capability name="jscriptversion"					 
  value="5.6" />
		<capability name="maximumRenderedPageSize"		
  value="800000" /> 		 
		<capability name="msdomversion"						 
  value="3.0" />
		<capability name="numberOfSoftkeys"					 
  value="2" />
		<capability name="requiresAbsolutePostbackUrl"	
  value="false" /> 		
		<capability name="requiresCommentInStyleElement"	
  value="false" /> 		
		<capability name="requiresHiddenFieldValues"		
  value="false" /> 		
		<capability
name="requiresOnEnterForwardForCheckboxLists"  value="false" /> 
		
		<capability name="requiresXhtmlCssSuppression"	
  value="false" /> 		
		<capability name="preferredImageMime"				 
  value="image/jpg" /> 	
		<capability name="preferredRenderingMime"			 
  value="application/xhtml+xml" />
		<capability name="preferredRenderingType"			 
  value="xhtml-basic" /> 
		<capability name="screenPixelsHeight"				 
  value="${screenHeight}" />
		<capability name="screenPixelsWidth"				
  value="${screenWidth}" />
		<capability name="supportsBodyClassAttribute"		 
  value="true" /> 			 
		<capability name="supportsCallback"					 
  value="true" />
		<capability name="supportsDivNoWrap"				
  value="false" /> 		
		<capability name="supportsNoWrapStyle"			
  value="false" /> 		
		<capability name="supportsSelectFollowingTable"		 
  value="true" /> 			 
		<capability name="supportsStyleElement"				 
  value="true" /> 			 
		<capability name="supportsTitleElement"				 
  value="false" />
		<capability name="supportsUrlAttributeEncoding"		 
  value="true" /> 			 
		<capability name="supportsXmlHttp"				
  value="true" />
		<capability name="tagwriter"						
  value="System.Web.UI.HtmlTextWriter" />
		<capability name="type"								 
  value="MSIE ${msieMajorVersion}" />
		<capability name="vbscript"							 
  value="true" />
		<capability name="version"						
  value="${version}" />
		<capability name="w3cdomversion"					
  value="1.0" />
		<capability name="win32"							
  value="true" />
		<capability name="xml"							
  value="true" />
	</capabilities>
</browser>

Whereas the WinCEbrowser section specifies the full format of the user agent in the <identification>section regular expression and extracts the various variable values using the same regular expression, the IEMobilesection takes a different approach. The regular expression in the <identification>section of the IEMobilesection matches any user agent containing the text IEMobilefollowed by a version number. The additional variable values are retrieved using separate regular expressions in the <capture>section.

Using this technique, as opposed to the more complex regular expression used in the WinCEsection, provides for a much more flexible solution. Rather than requiring that IEMobileand MSIEappear at specific points in the user agent, these less complex regular expressions simply require that the value exist somewhere in the user agent; there are no specific formatting requirements beyond that.

For information such as the screen size that is no longer in the user agent, the regular expression in the <capture>section retrieves that value from the header sent for specifically for that purpose, ua-pixels.

As mentioned earlier in this article, the capabilities of Internet Explorer Mobile on Windows Mobile 6 and Windows Mobile 6.1 exceed those of Internet Explorer Mobile on Windows Mobile 5.0 especially in the area of Document Object Model (DOM) support and other client-side scripting capabilities. The new IEMobilesection handles setting the capability properties for Internet Explorer Mobile on Windows Mobile 6 and Windows Mobile 6.1 to the appropriate values which are, of course, different than the appropriate values for Internet Explorer Mobile on Windows Mobile 5.0. There is, however, one challenge.

As you may know, Microsoft periodically releases Windows Mobile Adapter Kit Updates (AKUs) to Original Equipment Manufacturers (OEMs). These AKUs are updated versions of the Windows Mobile platform; they normally have bug fixes and other possible enhancements as compared to earlier releases of the same Windows Mobile version. Starting with Windows Mobile 5.0 AKU 3.3, Microsoft made a change to Internet Explorer Mobile that makes differentiating between Internet Explorer Mobile on Windows Mobile 5.0 and Windows Mobile 6 and Windows Mobile 6.1 slightly more difficult. Whereas Internet Explorer Mobile on most Windows Mobile 5.0 devices sends a user agent like that shown in the "Windows Mobile 5.0 User Agent" section earlier in this article, Internet Explorer Mobile on these later releases of Windows Mobile 5.0 sends a user agent formatted like those of Internet Explorer Mobile on Windows Mobile 6. The user agent from a post AKU 3.3 Windows Mobile 5 version looks similar to the following:

Copy Code
Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 6.8)

The problem here is that the new IEMobilebrowser section will incorrectly set the client-side DOM capability property as being a higher version than is actually supported by Internet Explorer Mobile on Windows Mobile 5.0. To address this problem, the WM6Plus.browserfile defines the following browser section.

Copy Code
<browser id="IEMobileNotAspNetAjaxCapable"
parentID="IEMobile">
	<identification>
		<capability name="version" match="6\.8" />
	</identification>
	<capabilities>
		<capability name="supportsCallback"  value="false" />
		<capability name="w3cdomversion"	value="0.0" />
	</capabilities>
</browser>

This <browser>section has a regular expression that matches a user agent containing IEMobile 6.8, the Internet Explorer Mobile version on Windows Mobile 5.0 AKU 3.3 and later AKUs. If the user agent contains this value, specific capability properties are set back to the appropriate values for Internet Explorer Mobile on Windows Mobile 5.0.

The remaining <gateway>sections in the WM6Plus.browserfile set those capabilities that may differ between different Windows Mobile 6 and Windows Mobile 6.1 devices. These <gateway>sections use header information beyond that available in the user agent.

Note:
For information on how <gateway>sections differ from <browser>sections see the Browser Definition Schema documentation in MSDN.

The first <gateway>section sets the color capabilities for the client device.

Copy Code
<gateway id="IEMobileColorScreenBitDepth"
parentID="IEMobile">
	<identification>
		<header name="UA-COLOR" match="color(?'bitDepth'\d+)"
/>
	</identification>
	<capabilities>
		<capability name="screenBitDepth"   value="${bitDepth}"
/>
		<capability name="isColor"		value="true" />
	</capabilities>
</gateway>

As you can see, this section simply extracts the color information from the ua-colorheader if it is available and sets the color capabilities appropriately.

The next two <gateway>sections are specific to Pocket PC-style devices: Windows Mobile 6 Classic and Windows Mobile 6.1 Classic, and Windows Mobile 6 Professional and Windows Mobile 6.1 Professional. This <gateway>section sets the inputTypecapability property from telephoneKeypadto virtualKeyboardfor Pocket PC-style devices.

Copy Code
<gateway id="IEMobilePPC" parentID="IEMobile">
	<identification>
		<header name="UA-OS" match="Pocket PC" />
	</identification>
	<capabilities>
		<capability name="inputType"	value="virtualKeyboard"
/>
	</capabilities>
</gateway>

The WinCEsection of the pie.browserfile sets the inputTypecapability property to telephoneKeypadbut we know that Pocket PC-style devices have at least a virtualKeyboard. If you're using a device that has a physical keyboard but the ASP.NET inputTypecapability is not set correctly, review the user agent and other headers for information that either identifies the presence of the keyboard or uniquely identifies the device that has keyboard, and then add a <gateway>section that sets the inputTypecapability to keyboard.

Finally there is the <gateway>section that sets the supportsFileUploadcapability property.

Copy Code
<gateway id="IEMobileUploadSupport" parentID="IEMobile">
	<identification>
		<header	 name="UA-OS"				match="Pocket
PC" />
		<capability name="canInitiateVoiceCall"
match="true"/>
	</identification>
	<capabilities>
		<capability name="supportsFileUpload"   value="true"
/>
	</capabilities>
</gateway>

The purpose of the identification tests in this <gateway>section may not be immediately obvious. The only Windows Mobile 6 and Windows Mobile 6.1 devices that support file upload capability are Windows Mobile Professional devices, but there is no header that differentiates between a Windows Mobile Classic and Windows Mobile Professional device. Without specific headers identifying the device type, this section must identify the device type by checking for the two identifying characteristics unique to Professional devices: the appearance of Pocket PC in the ua-osheader and support for making phone calls.

Note:
If you're unclear on how these two characteristics identify a device as a Windows Mobile Professional device, remember the fundamental characteristics of each device type. A Windows Mobile Standard device is identified as a Smartphone in the ua-osheader, a Classic device has Pocket PC in the ua-osheader but doesn't have phone support, leaving only Professional devices as having Pocket PC in the ua-osheader and the ability to initiate phone calls.

Using the New Capabilities File

Once you download the WM6Plus.browserfile, you need to add the file to the App_Browserssubfolder under your ASP.NET project. You can create the folder manually and copy the WM6Plus.browserfile that accompanies this article into the subfolder, or you can have Visual Studio create the subfolder with a default browser file and then replace the default browser file contents with that of the WM6Plus.browserfile.

To create the subfolder and browser file with Visual Studio, do the following:

  1. With your ASP.NET site open in Visual Studio, from the Visual Studio menu, select Website| Add New Item…

  2. In the Add New Itemdialog box, select Browser File, and then enter the Namefor the file. The file name can be anything you like as long as it has a .browserextension; I use WM6Plus.browser, which is also the name of the browser file in the accompanying download.

  3. Click the Addbutton.

Visual Studio then displays the message shown in figure 1.

Figure 1. Visual Studio confirming the creation of the new browser file in the App_Browser subfolder

This message is simply informing you that the browser file must be placed in the App_Browserssubfolder to work correctly.

  1. Click the Yesbutton.

Visual Studio automatically creates the App_Browserssubfolder if necessary, places a default version of the browser file in the subfolder, and then opens and displays the new browser file. The new browser file looks similar to figure 2.

Figure 2. The newly created default browser file

At this point, you need to replace the default browser file contents with the contents of the WM6Plus.browserfile in the accompanying download.

  1. Either copy the entire contents of the accompanying WM6Plus.browserfile and paste it over the default contents in the new browser file, or copy the WM6Plus.browserfile over the newly created browser file in the App_Browserssubfolder.

That's it, your Web site now has the information it needs to work properly with Internet Explorer Mobile clients browsing to your site from Windows Mobile 6 and Windows Mobile 6.1.

Conclusion

Windows Mobile 6 and Windows Mobile 6.1 offer the most powerful version of Internet Explorer Mobile to date. Most ASP.NET sites that work with Internet Explorer Mobile on Windows Mobile 5.0 devices should work equally well or even better with Internet Explorer Mobile on Windows Mobile 6 and Windows Mobile 6.1 devices. The appearance that your ASP.NET site does not work with Internet Explorer Mobile on Windows Mobile 6 and Windows Mobile 6.1 devices is simply a case of ASP.NET not having the information necessary to identify the browser capabilities; this issue is easily solved with the addition of a new browser definition file containing the proper capability property definitions.

See Also

Author Bio

Jim Wilson is president of JW Hedgehog, Inc. (http://www.jwhh.com) a New Hampshire–based consulting firm specializing in solutions, content creation, and mentoring for the Windows Mobile platform. Jim has worked extensively with the .NET Framework and .NET Compact Framework since the original beta release of each; he has over 20 years experience in the software industry including more than 14 years experience with relational database programming including SQL Server and SQL Server Compact Edition. Jim writes frequently for MSDN and has developed mobility curriculums for two of the industry’s leading technology training organizations, DevelopMentor and PluralSight. Jim speaks regularly at Tech Ed, the Professional Developer's Conference (PDC), VSLive, and the Mobility & Embedded DevCon. You will find Jim online at http://pluralsight.com/blogs/jimw.