My sessions at Tech Ed North America

Thu, May 29, 2008, 06:33 AM under Events
I have 2 sessions at Tech Ed in Orlando this year. Add them to your schedule.

- Wednesday 4th June, 16:30-17:45, MBL308 in room S230 G
Sharing Assets between the.NET Compact Framework and the .NET Framework

- Friday 6th June, 13:00-14:15, TLA318 in room S320 C
5 Cool Things to Know and Use for Smart Client Development with VS2008 and .NET Framework v3.5

Also after my session on Wednesday, between 10:00 and 18:30, together with my 2 co-authors we will be signing copies of our book at the bookstore - brings yours along for instant devaluation :)

I'll be around all week (Sunday 1st to Sunday 8th), so if you are in the area between those dates and you want to catch up over a pint or 3, ping me.

Silverlight 2 Beta 1 Namespaces – Part 4 – the WPF subset

Wed, May 28, 2008, 12:00 PM under Silverlight
Following from Part 1, Part 2 and Part 3, in this last part of the exploration I'll focus on the UI layer and I'll have even more of a statistical hat on.

11. System.Windows.dll is yet another Silverlight assembly with no direct counterpart in the full framework, but with tons of stuff inside (as evidenced by its size on disc and by the 21 namespaces!) that makes it the 2nd largest assembly. You can think of it as the brick that gives Silverlight its WPF UI. Its namespaces come from various v2.0 and v3.0 desktop assemblies as listed below (and it is in my opinion a prime candidate for refactoring):

-System.Net namespace with WebClient plus 6 related classes comes from the desktop's System.dll (!)

- System.ComponentModel comes from System.dll (! again) and is basically the BackgroundWorker implementation.

- 5 of its namespaces (System.Windows.Controls.Primitives, System.Window.Data, System.Windows.Documents, System.Windows.Resources, System.Windows.Shapes) and the System.ComponentModel.DesignerProperties class map to the desktop's PresentationFramework.dll

- 3 of its namespaces (System.Collections.ObjectModel, System.Collections.Specialized, System.Threading) map to WindowsBase.dll.

- 2 of its namespaces (System.Windows.Ink, System.Windows.Media.Imaging) map to the desktop's PersentationCore.dll.

- System.Windows namespace has a total of 61 types, coming from homonymous namespaces in PresentationCore.dll (e.g. FontStyle, RoutedEventHandler) and PresentationFramework.dll (e.g. Application, FrameworkElement) and WindowsBase.dll (e.g. DependencyProperty, Point) and also introduces some new types (e.g. AssemblyPart, ErrorType).

- System.Windows.Markup namespace with 2 types from WindowsBase.dll, 2 from PresentationFramework.dll and 1 from PresentationCore.dll.

- System.Windows.Media namespace which maps to PresentationCore.dll except for Matrix class from WindowsBase.dll and 5 new Silverlight types (MediaElementState, TimelineMarkerCollection plus 2 relatives and VideoBrush).

- System.Windows.Input largely maps to PresentationCore.dll, except for 2 classes (Key and ModifierKeys) from WindowsBase.dll and 1 class (KeyboardNavigationMode) from PresentationFramework.dll. There is also one new class in there: StylusInfo.

- System.Windows.Controls namespace has 24 types that come from PresentationFramework.dll (same namespace name of course). It also has 2 types (MultiScaleImage, MultiScaleSubImage) that make up the DeepZoom feature. It also has 3 types (2 from System.Windows.Forms.dll plus 1 brand new) that make up the OpenFileDialog feature.

- System.IO.IsolatedStorage.ApplicationSettings class has no counterpart in the desktop world and was touched upon here (scroll to the bottom).

- System.Windows.Interop namespace with 3 classes (Content, Settings and SilverlightHost) that is all new in Silverlight framework (even though that namespace name exists in various other WPF assemblies).


12. and 13. System.Windows.Controls.dll and System.Windows.Controls.Extended.dll
The overwhelming majority of the Silverlight controls reside in the System.Windows.Controls.dll assembly. The Extended.dll adds the Calendar, DatePicker, Slider and WatermarkedTextBox.


14. System.Windows.Controls.Data.dll
This adds a control not available at present in WPF: the Silverlight DataGrid. For all things DataGrid-related visit Scott's blog.

BackgroundWorker

Tue, May 27, 2008, 08:36 PM under dotNET | Silverlight
A cool class that was introduced in .NET Framework v2.0 is the BackgroundWorker. If you do any kind of UI development I encourage you to learn about this class (e.g. by following the links below), which makes it easy to execute long running operations on a separate thread, supporting cancellation, progress reporting and marshalling results back to the UI thread.


Back in 2004 I described what the class looks like (inc. links to MSDN) when I implemented it for the .NET Compact Framework v1.0/v2.0 (and for .NET Framework v1.1): BackgroundWorker. I also provided sample code to demonstrate the usage.

An added incentive to learn about it is that Silverlight 2 includes a fully interface-compatible version of BackgroundWorker. A good way to learn about it is by porting to Silverlight the desktop PI sample from my previous blog post and follow what the code does... have fun!

SideShow Managed Components v1.0

Tue, May 27, 2008, 03:25 PM under Links
Back in 2006 when Windows Vista was released I got very excited about the SideShow feature (the auxiliary display support). I got so excited that I wrote a series of long blog posts. Read bottom up my SideShow category.

I just got word that the team finally released the managed bits:
+ Windows SideShow Managed API 1.0 SDK.
+ Windows SideShow Managed Runtime 1.0.

I haven't played with the final release of the API, but I doubt it is that different to the Beta version that I used to record this SideShow screencast (in January 2007). If you spot any differences, let me know.

Silverlight 2 Beta 1 Assemblies – Part 3 – the v3.x subset

Tue, May 27, 2008, 05:03 AM under Silverlight
Following from Part 1 and Part 2, in this part of the exploration we look at assemblies in Silverlight that were introduced with the desktop framework's v3.0 and v3.5.

5. System.Runtime.Serialization.dll is an assembly with 3 namespaces introduced with .NET Framework v3.0 and it is also supported in Silverlight. System.Runtime.Serialization is present in the Silverlight implementation with most of the classes available. The System.Xml namespace in this assembly has support for the Dictionary but not for the MTOM, Binary or Text reader/writers.

6. System.ServiceModel.dll is a tiny subset of the full WCF v3.0 implementation. In a nutshell, 5 of the 15 namespaces are here and furthermore they are very thin with many classes missing and with existing classes missing members. Essentially, currently, Silverlight supports calling WCF services using the basicHttpBinding only.

7. System.ServiceModel.Web.dll is the assembly introduced in WCF v3.5 and, again, Silverlight only offers 1 namespace (out of the possible 10) and it only has the one self-explanatory type: System.Runtime.Serialization.Json.DataContractJsonSerializer.

8. System.Core.dll was also introduced in Fx v3.5 and I listed what it offers on item 9 here. The Silverlight variant offers the TimeZoneInfo class (but no custom timezone support), full LINQ to Objects support (System.Linq, System.Linq.Expressions and System.Runtime.CompilerServices) and just a drop from the System.Security.Cryptography namespace (Aes and AesManaged classes).

9. System.Xml.Linq.dll is an identical to its Fx 3.5 desktop counterpart. The only thing missing are the Save methods because in Silverlight we cannot arbitrarily save to the user's machine outside IS.

...and finally, not fitting with the title of this blog post, but included nonetheless...

10. System.Windows.Browser.dll is an assembly unique to Silverlight for now, and it offers the ability for managed code in a Silverlight app to interact with other browser elements. I described it fully at my HTML Bridge post.

Silverlight 2 Beta 1 Assemblies and Namespaces – Part 2 – the v2.0 subset

Mon, May 26, 2008, 07:29 PM under Silverlight
In a previous post I showed where we find the assemblies that make up the Silverlight 2 Beta 1 framework. Have a quick glance at the screenshots to remind yourself. Below, I follow up on the promise in my closing sentence of that blog entry.

1. mscorlib.dll includes almost 30(!) public namespaces, which means it is missing only about 20 namespaces compared to the desktop full version. Of course, even when the namespace exists in both versions of mscrolib, there are some types missing from the Silverlight version. In general terms the omissions are to do with: hosting, remoting, registry access, non-generic collections, serialization and some of the security types that are Windows-specific (e.g. System.Security.Principal/Policy/Permissions/AccessControl namespaces). We also find some types having members missing (e.g. the GC class does not have overloads of Collect that accept the generation to collect, no ThreadPriority etc) but nothing major. On the flip side, Silverlight adds some new sporadic members of its own e.g. a new NoOptimization value to the MethodImplOptions enum, and new attribute classes such as System.Security.SecuritySafeCriticalAttribute and System.Runtime.InteropServices.AllowReversePInvokeCallsAttribute. Generally speaking, there are tons of stuff in this assembly, the largest of them all in the Silverlight framework, so please explore on your own the compatible subset.

2. System.dll has just 6 public namespaces so it is 30 short of its desktop brother (but we'll see later that some of those are available in other Silverlight assemblies). The things truly missing though make sense such as: CodeDom, the specialized and generic collections (except for Queue and Stack which are present), configuration classes for reading appsettings, performance counters, tracing (but a thinner Debug class is present), EventLogging and SerialPort support. Whilst support for regular expressions is there, you cannot CompileToAssembly.

3. System.Xml.dll is missing the entire Xsl and XPath namespaces and even the support it has for Schema and Serialization is minimal at best (a total of 1 concrete class, 1 interface and 1 enumeration!). The main namespace (System.Xml) is almost fully implemented though with some additions as well (e.g. XmlXapResolver class and DtdProcessing enum) and notable omissions the Text reading/writing and the DOM model (XmlDocument and relatives).

4. System.Net.dll is a bit weird. You see, on the full framework there was a System.Net.dll introduced with .NET Framework v3.5 that had all the P2P stuff. However, the assembly here in the Silverlight framework has absolutely nothing to do with any of that! Instead, this assembly is all about sockets. On the full framework the implementation of sockets has always lived in System.dll (which we saw further up), so not sure why the factored out the 2 namespaces (System.Net and System.Net.Sockets) into this one. Maybe it is because, not only there are many types and methods missing, but also there has been some "butchering" that renders many things incompatible with each other (such as changing concrete classes/methods to be abstract, changing the type returned from various methods and adding new members to various places). The principles are the same though and, in a nutshell, you can connect back to your server asynchronously via sockets (but you cannot listen/accept).


Next time we'll see the Silverlight assemblies that stem from v3.0/v3.5 desktop counterparts.

For DevDays attendees

Fri, May 23, 2008, 04:44 PM under Events
Thank you for attending my 3 sessions in Amsterdam at DevDays 2008. I had a blast!

+ Resources for my Silverlight session.
+ Resources for my 5 Things (VS2008 client session).
+ Resources for my Parallel Extensions session.

Parallel Extensions session resources

Fri, May 23, 2008, 04:41 PM under Events | ParallelComputing
- Here are the slides (save as pptx).
- The demos were a subset of these videos: Samples, Task etc, Parallel class, PLINQ.

Thank you to those that attended my Parallel Extensions session earlier today at DevDays. I don't think I have ever seen so much interest in a technology before (I was answering questions for a good 20' after my 70' session ended). This is turning out to be one of my favourite talks – it just gives itself ;-)

My Silverlight session

Thu, May 22, 2008, 10:19 AM under Silverlight
I am giving a 75-minute Silverlight 2 Beta 1 session at various places and this blog post summarises the session pointing to resources for those that attended (and maybe useful for those that haven't).

You can download the entire PowerPoint slidedeck (save as PPTX) – it follows the following steps.

Step 1: First I go through 2-3 slides ensuring everybody realises that Silverlight is a cross-browser, cross-platform web technology that utilises .NET in the browser.

Step 2: Demonstrate some apps to give an idea of the kind of rich apps we can build - a subset of these samples.

Step 3: After a slide on what needs to be installed I move to the AGENDA. My AGENDA slide has 5 items on it, which are the following 5 steps (4 to 8).

Step 4: Getting Started aka Hello World.

Step 5: Intro to XAML inc. developer-designer interaction using Blend.

Step 6: HTML Bridge.

Step 7: Networking.

Step 8: IsolatedStorage and OpenFileDialog (i.e. File System Access).

Step 9: Finally, a summary pointing to your one-stop URL for Silverlight: silverlight.net.


Thank you to those that attended (or plan to attend) this session.

XAML: Level 100

Mon, May 19, 2008, 03:29 PM under dotNET | Silverlight
Since you are reading my blog, chances are that you are a .NET developer. Do you realise that eXtensible Application Markup Language (XAML) is now part of .NET? Are you familiar with it? How would you describe XAML (pronounced "zammel") to someone that is not familiar with it if you only had 10-20 minutes? Below is my take.

Background
XAML was introduced as part of Windows Presentation Foundation (WPF) which was released in November 2006 as part of .NET Framework v3.0. In addition, XAML is at the core of Silverlight, v2 of which will be released this year. Whilst XAML itself is independent of those two technologies, I am a practical person so I associate XAML with those two presentation technologies (WPF for the Windows desktop and Silverlight for the cross-platform browser) and have no qualms in intermixing those terms in this blog post. The XAML that Silverlight 2 will support is a subset of the XAML that WPF supports but the core principles and most capabilities are the same.

XAML is an XML language for describing a hierarchy of objects and their properties; in our concrete examples, it describes a hierarchy of visual objects that make up a Graphical User Interface (GUI).

Relationship to managed code
An important fact about the XAML elements (more precisely the WPF/Silverlight graphical system and controls) is that they are fully composable. For example, the following screenshot shows some crazy XAML that places a TextBox inside a button as its content (and in the bottom right corner the result):

It is important to note that anything you can do with XAML, you can also do in code (C#, VB etc). For the previous example, the alternative code required is a single statement in the ctor:

Regardless of that important fact, it is our preference to use XAML for the (naturally) declarative part of describing a GUI. We then use code, of course, to programmatically react to user interaction with the GUI elements that were declared in XAML, i.e. we use code to capture the behaviour.

The obvious question that arises is how we connect the XAML bits to our managed code. In brief, the technique of partial classes ensures that the XAML bits and the managed code bits end up making a single class. XAML properties assign names to controls so we can reference them in the code-behind and, finally, XAML properties connect events in XAML to event method handlers in code. The following screenshot shows a GUI where clicking on the button, updates the time in the textbox.


Take a look at the combination of XAML and C# to achieve this.


Tool Support and the Designer-Developer Workflow
Visual Studio 2008 has a designer tool that allows you to type XAML (with full intellisense) and instantly see the results. For WPF projects it allows you to also drag and drop controls onto the surface and have the XAML generated for you. Have a look at this VS2008 screenshot of Silverlight designer.

For Silverlight 2, the VS2008 is just a read-only designer so you have to type things in the XAML pane or use an external tool to generate the XAML such as Expression Blend.

Expression Blend allows your designer friends to work on the same project/solution and more importantly on the same XAML that you, the developers, are working on.


Have a look at the screenshot of the exact same project you saw just now, but this time in Blend.

That is one of the reasons XAML is an XML-based language: XML is very toolable. Because of that we have a nice workflow between designer people in Blend and developer folk in VS2008, where there is no exchange of bitmaps or binaries but they are both truly working on the same asset: XAML files. The designer-developer interaction for WPF with XAML is described in this paper.

In my relevant demo, I use Blend to style the Button, add a storyboard for animating it and changing the background color to the LayoutRoot to a gradient color. You can see glimpses of that in both of the above screenshots of VS2008 and Blend, so revisit them paying attention to the XAML parts.

Concepts Worthy of Further Exploration (MSDN links)
If you are a seasoned .NET developer, you'll find that XAML/WPF/Silverlight introduce some new concepts. Below I list MSDN links to the top 5 areas I recommend you investigate – just follow the hyperlinks.

- The Layout System. Note that from the list of layout panels, Silverlight 2 only supports Canvas, StackPanel and Grid. Explore all 3 by changing the LayoutRoot type and dragging various controls on it. This is a good time to grok Attached Properties.

- Dependency Properties. These are important to understand because they enable the following 3 equally important areas:

- Animations (in my session I make a button fly around a bit when clicked).

- Databinding (in my session I bind the results of a WCF call to a list).

- Control Styling/Templating (in my session I change a button to look like a happy face)

Conclusion – XAML levels of competency
If you have been ignoring XAML so far, I don't think you can afford to do so any longer. IMHO there are 4 levels of XAML competency:

Level 100 – truly understand all of the above.

Level 200 – confidently read XAML (e.g. as spat out by VS2008 or Blend).

Level 300 – be able to type XAML yourself with an aim to create a structure of a bland GUI (setting basic properties and hooking events etc).

Level 400 – create styles, templates, animations and set gradient colours by hand.

Video recording of my Greek presentation online

Sat, May 17, 2008, 03:59 PM under Events
5-6 weeks ago I presented at the Greek 2008 Launch (as I mentioned here). The recording is now live online (in a cool Silverlight player). Watch it here.

Mobile Book in Chinese

Sat, May 17, 2008, 03:54 PM under MobileAndEmbedded
Catching up with my inbox I found a message that our book is now translated to Chinese! Peter beat me to it with sharing the news so go over to his blog post with an image of the cover.

Parallel Extensions library is well received

Sat, May 17, 2008, 03:52 PM under Events
Last week I presented a session on Parallel Extensions in Glasgow (as I mentioned here).

Colin posted the speaker scores from the multitrack event and those scores IMO directly reflect the fantastic job the product team has done on this technology – it "sells" itself really. I look forward to delivering a slightly longer version of the talk in a few days at DevDays.

The session is 4 demos strung together that are subsets of my 4 screencasts (Samples, Task etc, Parallel class, PLINQ), so watch them and forget the slides.

FAQ - What do I need to develop Silverlight 2 Beta 1 apps

Tue, May 13, 2008, 07:43 AM under Silverlight
Based on questions I receive, there seems to be some confusion as to what needs to be installed in order to develop Silverlight applications.
You only need ONE download: Silverlight 2 Beta 1 Tools for Visual Studio 2008 RTM (notice the file name is "chainer"). Note that this is not compatible with the recently released Orcas SP1.
Optionally, if you have designer friends or you are a graphically inclined developer, you can download the Expression Blend 2.5 CTP (build 2.1.1113.0 is the one that also works with .NET Framework v3.5 SP1). The truth is that if you aspire to create truly rich Silverlight applications, you will need to hire designer people and have them use Blend.

The confusion arises because we have other downloads, which are actually included with the chainer install at the top so no need to install separately:
1. Runtime - essential as this is the actual SL plugin (and also the only thing end users need to install – about 4MB taking about 4-10 seconds)
2. SDK - Includes the asp:Silverlight control that you place on aspx pages and also a whole bunch of Silverlight assemblies that you may wish to use (and deploy) with your Silverlight application.

If you are having trouble getting everything installed, read this highly referenced post and if you are still having problems post them to the dedicated forum.

Silverlight Example Apps

Mon, May 12, 2008, 06:32 AM under Silverlight
I've seen introductory sessions where people jump straight into Visual Studio and/or Blend and start demonstrating how to build a Silverlight application. IMO, Silverlight is a relatively new technology and there are potentially people that have not seen examples of applications built with it. As such it is important to demonstrate its capabilities first by running some applications and clicking around. There are many samples to choose from the Showcase and from the Gallery, so take your pick.

In my sessions I show my favourites (i.e. the ones that appeal to me personally, for one reason or another).

1. Hard Rock Memorabilia (shows the DeepZoom feature in a public released site)
2. Silverlight Airlines (gets you thinking of great user experience for booking a flight)
3. Cameras (another example of great user experience for shopping online scenario)
4. Image Snipper (shows graphics and interaction you would only expect from a desktop app)
5. Video Puzzle (combination of a game with video elements)

...then before jumping into code, it is worth showing some of the controls that are available and also how they can be skinned (templated):
6. Control Demo (not all of them, but gives you an idea)
7. Corina's control skins Flat, Bubbly, Red, Rough.

...if you are looking for a sample that combines skinning, the OpenFileDialog, IsolatedStorage and also throws in a bit of extensibility, do check this out:
8. Calculator (get its story from the author's blog post)

Finally,
9. a great business application that is almost indistinguishable from a local client and has only recently been made available is the Healthcare Demo (built in the UK).

What publically available Silverlight application(s) float your boat?

Last Flash issue for me

Thu, May 8, 2008, 01:48 AM under Links
In last’s week Flash issue, I wrote 500 words About Silverlight 2.

I have enjoyed being the editor of the UK MSDN Flash newsletter. Ever since I took it over, it has topped Microsoft's (worldwide) newsletter growth stats compared to previous years in more areas than one. Additionally, its format inspired other newsletters from other Microsoft subsidiaries outside the UK. Hope you don't mind me blowing my own horn and since I can't publically back up these claims with numbers, you'll just have to take my word for it ;-). Exactly a year after the first issue I edited, the time has come for me to hand the newsletter back and I look forward to receiving it with a bit more anticipation as to what content I'll find inside!

Thanks to everyone that stayed tuned to that Flash feed, and I also hope you'll stay tuned to my blog feed.

LINQ to XML, namespaces and VB

Tue, May 6, 2008, 06:30 AM under dotNET | LINQ
Recently I was playing with some LINQ to XML for a demo I was preparing and was having trouble retrieving the expected values from what was a very straightforward query.

Have a look at the XML file that looks like this (the results of programmatically calling this Amazon service).

Each Item element represents a book and I wanted to retrieve the Title. How would you form that query with LINQ to XML?

I went for the obvious:
  var res =
from ia in XElement.Parse(e.Result).DescendantsAndSelf("ItemAttributes")
select ia.Element("Title").Value;
When that did not produce the expected results I scratched my "tired" head at the time and pinged MikeT who came up with the correct way of doing this (you still have time to work it out on your own).

The clue (and at the same time further "excuse") is that all my previous experiments with LINQ to XML involved using my own demo XML files that never had namespaces inside so I forgot all about them (haven't paid the tax in a while). I find quite ugly what you have to do to incorporate namespaces in a LINQ to XML query, but there seems to be no nicer alternative to the following (thanks Mike):
void SomeMethod()
{
var res =
from ia in XElement.Parse(e.Result).DescendantsAndSelf(n("ItemAttributes"))
select ia.Element(n("Title")).Value;

// TODO use res
}

static XName n(string name)
{
return XNamespace.Get("http://webservices.amazon.com/AWSECommerceService/2005-10-05") + name;
}
I still didn't like this solution for the simple demo I wanted to use it for. So, I recalled VB's superior support for XML and I converted the project to VB and used the following instead which needs no extra method and is all round more elegant:
  Dim res = _
From ia In XElement.Parse(e.Result)...<n:ItemAttributes> _
Select ia...<n:Title>.Value()
...and if you are wondering where the n comes from, that is at the top of the VB file:
Imports <xmlns:n="http://webservices.amazon.com/AWSECommerceService/2005-10-05">
...another aspect of VB's beauty and another thing I had the opportunity to mention in my demo ;-)

Lenovo Fn key

Sat, May 3, 2008, 03:52 PM under UserInterfaceDesign
Very recently I received (from work) a new laptop: Lenovo T61p (to replace my aging Toshiba M5). There are quite a few gotchas with setting up this machine (e.g. I wasted an hour trying to get it to see a second internal drive), but I will spare you my setup/installation experience. Instead, you may be interested in Keith's helpful post here. Generally, I am happy with this machine from a performance perspective.


There is however the quite important issue of its keyboard: it's the laptop keyboard from hell. Why the "£$^&* don't we have a universal standard for laptop keyboards yet? The placement of keys on this laptop is weird (e.g. the ESC key is further up than the top row of keys instead of being aligned with the Function keys) and also keys I usually expect to be more easily accessible than other keys (e.g. up, down, left, right arrow keys) are actually... smaller and cramped close to the others!

However the biscuit goes to the Fn key placement in relation to the Ctrl key. I expected the Ctrl key to be firmly placed in the bottom left and for it to be larger than other keys. Instead, the Ctrl key is normal size and it is 2nd from the bottom left, its place taken by the rarely used Fn key! What is worst is that, apparently, there is no keymapping software that can fix this, since Lenovo in their wisdom have made it permanent in the firmware :-(

One of the worst examples of how this trips me up is copy/paste (Ctrl+C, Ctrl+V). I have some source window where I do a copy (but in reality I only did an Fn+C without realising it) and then close the window, switch to my target window and do a paste (in reality a Fn+V) and nothing happens. Then I realise my mistake but it's too late to do a Ctrl+V now since the copy was never actioned... Arghh!

If you think that I am overreacting, first try using a keyboard like that before passing judgement. If you own one and think I am overreacting, clearly you haven't tried pressing Ctrl+Shift+B (Build Solution in Visual Studio) or Ctrl+Shift+Esc (bring up Task Manager) with just one hand (impossible!). Anyway, it looks like I am not alone judging by the collections of complaints here, here, here and here amongst other places.

My partial solution: I removed the offending key completely (screenshot).

As an unrelated aside, the Mac Air suffers from the same bewildering choice of placement of the Fn and Ctrl keys. As a more related aside, if you see me struggling to type in my upcoming events, now you know why!

<end of rant/>