The blog of dlaa.me

Fixes and features by popular demand [AJAX Control Toolkit update!]

Earlier today we made available the 10606 release of the AJAX Control Toolkit. This release focused on addressing many of the most popular bugs and work items identified by the user community in the support forum and online issue tracker. We've also added some new functionality to the Toolkit that really improves the user experience for page authors and consumers alike!

The release notes from the sample web site detail the improvements:

General fixes:

  • Design Mode support:
    • Tabs designer: Tabs control can be configured in the designer.
    • PageMethods in code-behind: Extenders that consume web services can now have PageMethods added to code-behind automatically when using the designer. A repair mode fixes existing PageMethods with incorrect signatures.
    • Control icons: Toolkit controls have more meaningful icons that show up in the Visual Studio Toolbox when the Toolkit DLL is added to it.
  • Dynamic context: Toolkit extenders that consume web services can now pass additional context beyond what is used by the default web service signature.
  • Validators and Toolkit extenders: Extenders that target TextBoxes with ASP.NET validators attached to them no longer interfere with the validation process.
  • Animation support: Toolkit controls that build on top of PopupBehavior now have generic animation support built in.
  • Script combiner: When the ToolkitScriptManager is used, Toolkit scripts are downloaded in a single, common JavaScript file instead of multiple files. This allows for faster downloads and fewer roundtrips. The combined file is generated dynamically depending on the controls being used on the page. All Toolkit sample pages use this new functionality.
  • Events support: Toolkit controls fire events for core actions. This is in part to make plugging in animation easier and also to allow users to hook into the various Toolkit controls' behaviors and perform custom actions.
  • Bug fixes: This release includes fixes for over 120 issues tracked in the Toolkit Issue Tracker representing over 750 user votes.
  • Accessibility fixes: Slider and AutoComplete have support for high contrast and some controls like AutoComplete, NumericUpDown, CascadingDropDown and DynamicPopulate which issue XmlHttpRequests update a hidden DOM element to automatically refresh the JAWS screen buffer to reflect new data.

Control updates:

  • MaskedEdit extender works well with the Calendar extender and the ValidatorCallout extender when targeting the same TextBox.
  • AutoComplete supports scrolling in the fly-out, multi-word, first word default selection and it has animation built into it.
  • ModalPopup fix for most common scenarios involving absolute and relative positioning.
  • NumericUpDown has new Minimum and Maximum properties to restrict the range of numbers allowed.

Visual Studio Codename "Orcas" support:

  • The Toolkit DLL works with ASP.NET AJAX Orcas Beta 1 DLLs and there are no breaking changes.

For more details about the Tabs designer, web service design-time enhancements, and script combining (along with some pretty pictures!), check out Shawn Burke's release announcement.

As always, it's easy to sample any of the controls right now (no install required). You can also browse the project web site, download the latest Toolkit, and start creating your own controls and/or contributing to the project!

If you have any feedback, please share it with us on the support forum!

PS - The public sample site hasn't been deployed quite yet (real soon now!), but the new Toolkit bits are up on CodePlex, so feel free to get them and start using them!

Silverlight "Surface" Demonstration [Silverlight implementation of Surface's "photo table" UI]

Yesterday, Microsoft announced its Surface product to much buzz and excitement. The demo videos I saw featured a "photos on a table" user interface that displayed a handful of photos sitting on the Surface. The interface allowed people to easily move the virtual photos around by touching them in the center and sliding them to a different location on the screen. By touching the corners instead, photos could be sized and rotated with ease.

It struck me that this interface would be pretty easy to replicate with Silverlight and I decided to do so as a learning exercise. I spent some time on this last night and tonight and came up with an application that looks like this:

Silverlight "Surface" Demonstration

You can click here (or on the image above) to play with the application in your browser. The code's quite simple; click here to download the source code and play around with it yourself! (To build the project, you'll want to use Visual Studio Orcas Beta 1 and the Silverlight Tools.)

Notes:

  • When the application loads, it randomly lays out the sample photos. To interact with a photo, simply move the mouse pointer over the photo and click+drag on one of the yellow control elements that appears. The center element moves the photo around and the corner elements all rotate/resize it. Click on any part of a photo to bring it to the top of the pile.
  • Without the snazzy Surface hardware support, this application doesn't support the Human Finger 1.0 input device. :) However, if you run it on a Tablet PC or hooked up to something like the Wacom Cintiq, you can get pretty close.
  • As expected, Silverlight's XAML support makes this kind of interface pretty easy to build. I understand the Surface UI was written using WPF (Silverlight's big brother), so I suspect some of the techniques they used are fairly similar to what's being done here.
  • The sample images are a few of my favorite wallpapers that come with Windows Vista. I have not included them with the code download because they're large and it's easy enough to copy them from your own %windir%\Web\Wallpaper directory. Or just use your own favorite images!
  • I don't demonstrate it here (partly because I don't have a good nature video), but it would be easy to add video support so that each of the photos was a streaming video instead. Hum, maybe I'll do a follow-up post... :)

It's pretty obvious that XAML lets you do some pretty neat things with ease - I look forward to even more compelling new interfaces based on Silverlight and WPF!

Lighting up the XML Paper Specification [Proof-of-concept XPS reader for Silverlight!]

Since getting involved with Silverlight and finding out the XPS document type WPF enables has XAML at its core, I've been wondering how Silverlight would do as a lightweight XPS viewer.

First, a bit of background: WPF is the Windows Presentation Foundation and represents a new approach to UI for Windows. XPS refers to the XML Paper Specification, a device-independent file format for flexible document representation (think PDF) that's part of Office 2007 and .NET 3.0. WPF offers rich support for displaying XPS documents via its DocumentViewer and XpsDocument classes (among others). Because the 1.1 Alpha release doesn't currently include the relevant classes, Silverlight wouldn't appear to be well suited for XPS document display at first glance...

However, Silverlight does have the Downloader class which includes support for packages (for the purposes of this discussion, packages are basically just ZIP archives). Since an XPS document is really just a package, and the core document format XPS uses is XAML, and Silverlight speaks XAML (well, at least a subset of it!), maybe it's not such a stretch to do XPS with Silverlight after all.

I thought it would be a neat exercise to try to write an XPS viewer with the publically available Silverlight 1.1 Alpha bits so I gave it a try and ended up with an application I call SimpleSilverlightXpsViewer:

SimpleSilverlightXpsViewer Application

Go ahead and click here (or on the image above) to play around with the application in your browser. If you find yourself wondering how it works, just click here to download the complete source code/resources and play around with it yourself! (To build the SimpleSilverlightXpsViewer project, you'll want to use Orcas Beta 1 and the Silverlight Tools.)

Of course, this is just a proof-of-concept application built on an Alpha platform, so there are some rough edges. :) Some notes are in order:

  • I created my own XPS documents so I wouldn't have to worry about getting permission to use someone else's XPS documents. Office 2007 comes with a handy "Microsoft XPS Document Writer" printer driver that lets you create an XPS document from any application simply by printing to the XPS "printer" (which then saves the resulting output to a file you specify). I created the three sample documents this way: the "Intro" document came from a simple Word document, the "Blog" document came from my blog via IE7, and the "Site" document came from the Silverlight Forums via IE7 with a landscape page layout.
  • Because the only kind of XPS document I've worked with is the kind the XPS printer driver outputs, there's a very good chance SimpleSilverlightXpsViewer won't understand the internal format of other valid XPS files. Remember, though, that I didn't set out to write an XPS file parser - I just set out to write a simple XPS viewer for Silverlight. :)
  • The translation of "XPS XAML" to "Silverlight XAML" is done by the XpsToSilverlightXamlReader class, a minimal derivation from XmlReader that performs on-the-fly modification of the "XPS XAML" to translate it into "Silverlight XAML". Specifically, some elements are renamed, some attribute values are tweaked, and some attributes are removed entirely. The tweaking is done to address the Glyphs.FontUri/ImageBrush.ImageSource issue mentioned next and re-points the relevant content to an external location.
  • XPS documents are entirely self-contained, with any necessary fonts and images embedded in the file (package) itself. This is great for simplifying distribution and Silverlight's Downloader class makes it easy to get at individual files in a package. However, SimpleSilverlightXpsViewer works best when the images and the fonts are extracted from the XPS file:
    • Under the right conditions, embedded images can be fetched by Silverlight by using the ImageBrush.SetSource method. However, things tend to break if there are multiple references to the same image in a single page (an exception is thrown when the second call to SetSource is made), so SimpleSilverlightXpsViewer doesn't enable this by default. Interested parties can #define SETSOURCE (for both C# files) to experiment with this feature (things work fine for the first page of all of the sample documents, but break on the second pages of the Blog and Site documents).
    • The default behavior of Glyphs.FontUri does not seem to automatically pull the font out of the package - at least not as it's used by SimpleSilverlightXpsViewer (possibly because Silverlight doesn't seem to like the leading '/' on package-relative paths). TextBlock has a SetFontSource method that seems interesting, but XPS XAML uses the Glyphs class which doesn't seem to support SetFontSource.
  • For some reason, the XPS documents generated by the XPS printer driver aren't directly open-able by Silverlight's Downloader (a COM exception is thrown). However, I've found that a quick un-ZIP/re-ZIP with either of my favorite ZIP tools yields XPS documents that open right up. I suspect this is due to a simple issue with the Alpha Downloader implementation (endian-ness of the ZIP file, some special section embedded by the XPS printer driver, etc.) that could be fixed by the Silverlight team without much difficulty.
  • Silverlight doesn't support the TIFF file format (which is not surprising because full support can be quite complex and TIFF images are hardly ever used on the web). As it happens, XPS printer driver output may contain TIFF images (it seems they're used as a mask of some kind behind another PNG or JPG image) - SimpleSilverlightXpsViewer simply ignores the TIFF images and neatly side-steps the support issue. :)

While SimpleSilverlightXpsViewer is a cute proof-of-concept application I enjoyed writing, it is hardly the final word on Silverlight XPS support. (Hey, I'm not even on the Silverlight team!) I don't know what the official plans are for more formal XPS support in the Silverlight platform, but my experience with SimpleSilverlightXpsViewer suggests that most of the pieces are already in place for a pretty reasonable XPS experience with the Silverlight 1.1 Alpha. Throw in a couple of tweaks to Silverlight (and/or SimpleSilverlightXpsViewer!), and it should be possible to provide a pretty compelling XPS-like user experience for Silverlight!

The web just got even better... [Silverlight announced at MIX07!]

During his keynote at the MIX07 conference in Las Vegas, Scott Guthrie showed off some of the power of Microsoft's recently announced Silverlight platform. In particular, the ability to easily run managed code in the web browser - coupled with a powerful rendering engine - seems like it will to radically change the landscape of the web. My team had the privilege of writing the Silverlight Airlines demonstration he used to show off just how easy it is to develop with Silverlight. Demoed on stage, it looked something like the following image:

Silverlight Airlines Demonstration

Now that your appetite is whetted, go ahead and click here (or on the image above) to view the demo in your browser with the Silverlight 1.1 Alpha thanks to the seamless cross-browser, cross-platform support that Silverlight provides.

When our manager Shawn Burke asked us to put this demo together, my coworker Ted Glaza and I had practically no experience with Silverlight or WPF. So we spent about a week playing around with the technology to learn how it worked. By that time, the general concept of the demo was fairly well established and we spent time the next week developing the foundations of the application. Before long, we had a working demo that we showed off to Scott. The third week was spent incorporating visual feedback from a designer and adding some finishing touches. For those of you keeping track at home, that's one cool app written by two developers in just three weeks - beginning with nothing and building on top of a platform that was still being developed - pretty compelling, I think!

In the spirit of openness and learning, you can click here to download the complete source code for this demo application and play around with it yourself!

A few notes on the application:

  • It's implemented as three self-contained controls (the map, calendar, and itinerary picker) that are hooked together via a couple of simple event handlers and property accessors.
  • The goal of code/design separation was achieved here to an extent I haven't experienced before. In particular, the fact that we were able to incorporate an external party's XAML design into our existing code with such ease was a rare treat.
  • I experimented with a vaguely CSS-y approach to XAML design with the calendar and itinerary picker controls I wrote, overlapping a number of different styles and using opacity to display the right style at the right time. I liked the way it worked out here because it enabled me to (for example) completely define the look of the calendar's day cells in a single XAML file - even though that style is actually somewhat complex (there are different styles for alternating months, weekends, hovering, selection, etc.).
  • The "plane flying" animation was Ted's doing and adds a really nice effect. All it took to implement was a plane graphic, a few transforms, a couple of animations, and a bit of high school math. :)
  • The XAML content is automatically resized to fit the browser window (while maintaining its original aspect ratio) with some JavaScript code that hooks the Silverlight control's onLoad and onResize events and manipulates two simple transforms it creates for that purpose. Silverlight lets you program against it with C# and JavaScript - at the same time!
  • In order to compile and build the source code, you need Visual Studio "Orcas" Beta 1 and the Silverlight Tools installed on you machine. Complete details and download links for these tools (and others) can be found on the Silverlight web site.
  • The inspiration for the demo application came from Bret Victor's Magic Ink essay which is a great read and recommended for anyone who's interested in user interface design.

The Silverlight Airlines demo was a fun project to work on - I look forward to be seeing (and doing!) a lot more with Silverlight in the coming days!

PS - Since the keynote presentation, there has been some interest in reusing the calendar control. Beyond making the source code available here, I may write a follow-up blog post going into more detail about the calendar itself. As a quick teaser: it's capable of more sophisticated display than what's in the demo application. :)

PPS - If you watched the Scott Guthrie keynote, you probably saw that there was a time Scott tried to switch the display screen over to the Mac to demonstrate something and it took a while for the conference's A/V folks to actually make the switch. A couple of people have asked if this delay was due to a problem with the Mac or Silverlight. I happen to have been sitting backstage mere inches away from the Mac in question (conferences use KVM switches to keep all the demo machines backstage) and I can assure you that there was no technical issue with the Mac or Silverlight. Aside from the conference tech taking a little while to switch the display over, there were no technical glitches during the demo. :)

Toolkit patching made easy [Announcing the AJAX Control Toolkit Patch Utility]

We've just made available the AJAX Control Toolkit Patch Utility, a simple ClickOnce application that makes it easy for *anyone* to contribute fixes to the AJAX Control Toolkit!

Background: We have a very active user community that's using the Toolkit in lots of ways we never imagined. Sometimes people come up with better ways of doing things and occasionally they bump into a new issue we didn't know about. When questions show up on the support forum, it's great to see someone follow up with a change to the Toolkit that resolves the issue. These community contributions are fantastic - we always try to add a pointer to the associated work item for the issue so we won't forget about it. However, there is a fair amount of effort involved in merging such fixes into the Development branch of the source code and that effort can delay the incorporation of proposed changes. The new Patch Utility is designed to streamline the process so it will be easier for people to contribute fixes and easier for the Toolkit team to incorporate them into the next release of the Toolkit. By making the process simpler and enabling the inclusion of more community fixes, everyone benefits by having a better Toolkit that they're less likely to have trouble with!

How patching works: The AJAX Control Toolkit Patch Utility Guide contains all the details - along with screenshots that walk through everything. The process itself is pretty simple. Once a Toolkit user identifies a problem, he/she runs the Patch Utility in "Create a Patch" mode which walks through the steps of downloading the latest Development branch of source code for the Toolkit. The user makes whatever changes to the Toolkit are necessary to fix the problem and alters the automated test cases to verify the new behavior. Then the user runs the Patch Utility again in "Prepare Patch for Submission" mode which collects the changes that were made, gives the user an opportunity to review them in a file differencing tool, and generates a compact ZIP archive containing the user's patch. The user attaches the ZIP file to the existing work item that corresponds to the issue he/she fixed and that's it!

What happens next: On the back end, we have a process running which periodically looks at outstanding work items for new patches. When a new patch is found, a set of "check-in-able" changes is automatically created for that patch. What that means for the Toolkit team is that it's easy for any of us to review the patch, merge it with the very latest version of code in the Development branch, test it on our machines, and check the patch in for inclusion with the next Toolkit release!

What changes make good patches: Bug fixes and minor enhancements to existing code make great patches because the overall amount of change is small and the effect of the change is fairly self-contained and easily testable. On the other hand, broad changes like the addition of an entirely new control or the refactoring of a significant chunk of code would not make good patches due to the widespread effects of such changes (we have a different process in place for such things; email us if you want to add a new control).

The Patch Utility enables anyone to make fixes to the Toolkit - if you're a Toolkit user and you've got a fix floating around on your machine, please use the AJAX Control Toolkit Patch Utility to submit it! And if you have any suggestions for things we can improve please send your feedback to us!

AutoComplete++ [How to: Create a multi-word auto-complete text box]

By default, the AJAX Control Toolkit's AutoComplete extender doesn't have a notion of "words" and will try to auto-complete whatever text is currently in the text box, treating what's there as a single "word". One request that has come up a few times was for the ability to auto-complete multiple words individually. According to the comments of that work item, it looks like someone's made a set of proposed changes to do just that! It's great to have such an involved user community!! (Please note: The work item comments suggest those changes don't work in all browsers.)

One thing I'd been meaning to do was write a quick sample of how to get reasonably good multiple-word auto-complete without making any modifications to the released AutoComplete extender. In other words, you can use the latest official Toolkit release (10301 in this case) and get some nice multi-word completion today. The key observation here is that the Web Service used to provide the list of candidate words has all the information it needs to do multi-word completion as well:

Multi-word auto-complete example

The complete code for the sample page is included below for anyone to look at or modify for their purposes. A few notes about the code:

  • The example was written to be simple, not efficient. The goal is to demonstrate the idea as plainly as possible, so there's no focus on performance.
  • The code works by auto-completing the last "word" of input and then populates the list of candidates with the resulting words and the preceding text.
  • All comparisons are case-insensitive so the user can type however they want.
  • In a real-world application, the list of candidate words would probably be retrieved from a helper function, a database, etc..

Here's the complete ASPX file:

<%@ Page Language="C#" %>

<%
@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit"
    TagPrefix="ajaxToolkit" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<
script runat="server">
    [System.Web.Services.WebMethod]
    [System.Web.Script.Services.
ScriptMethod]
    
public static string[] GetCompletionList(string prefixText, int count)
    {
        
// Fetch and sort the list of available completion words
        string[] allWords = "AJAX Control Toolkit AutoComplete auto automatic".Split(' ');
        
Array.Sort(allWords);

        
// Split input into completed words and prefix characters for the current word
        // Match on the current word and return candidate list including completed words
        // Ex: "he" -> "" and "he..."
        // Ex: "hello there th" -> "hello there " and "th..."
        string completedWords = "";
        
string prefixChars = prefixText;
        
int lastSpace = prefixText.LastIndexOf(' ');
        
if (-1 != lastSpace)
        {
            completedWords = prefixText.Substring(0, lastSpace + 1);
            prefixChars = prefixText.Substring(lastSpace + 1);
        }

        
// Create the completion list by searching for prefix matches
        System.Collections.Generic.List<string> completionList =
            
new System.Collections.Generic.List<string>();
        
foreach (string word in allWords)
        {
            
if (word.ToUpperInvariant().StartsWith(prefixChars.ToUpperInvariant()))
            {
                completionList.Add(
string.Concat(completedWords, word));
            }
        }

        
// Return the completion list
        return completionList.ToArray();
    }
</script>

<
html xmlns="http://www.w3.org/1999/xhtml">
<
head runat="server">
    <title>Multi-Word Auto-Complete</title>
</
head>
<
body>
    <form id="form1" runat="server" onsubmit="return false;">
        <asp:ScriptManager ID="ScriptManager1" runat="server" />
        <asp:TextBox ID="TextBox1" runat="server" Width="300" />
        <ajaxToolkit:AutoCompleteExtender ID="AutoCompleteExtender1" runat="server"
            TargetControlID="TextBox1" ServiceMethod="GetCompletionList"
            MinimumPrefixLength="0" />
    </form>
</
body>
</
html>

Enjoy!

Toolkit talk two-fer! [Spoke at the ASP.NET Connections conference]

Earlier today I presented two talks about the AJAX Control Toolkit at the ASP.NET Connections conference in Orlando, Florida: AMS305: ASP.NET AJAX Control Toolkit: See How to Take Advantage of the ASP.NET AJAX Control Toolkit and AMS304: ASP.NET AJAX Control Toolkit Unleashed: Creating Rich Client-Side Controls and Components.

The content for these talks was based on stuff I've previously presented at TechReady4 in February and ASP.NET Connections in November of last year. However, this time around I was able to go into quite a bit more detail because I had over twice as much time to speak and do demos. The introductory AMS305 talk took the ImageFlix sample I've used before and expanded on it to demonstrate the Toolkit's new support for ASP.NET Skins/Themes and advanced animations followed by a quick walkthrough of what to do when things don't work like you'd expect (demonstrated here by adding a DropShadow to the popup panel). The more advanced AMS304 talk used an updated FontSize extender demonstration like the one that was demonstrated at the November ASP.NET Connections and included an overview of working with the Toolkit project, highlighting the automated testing framework and new localization support. Overall, there are about 15 completely new slides with fresh content, covering topics such as localization, automated testing, and more.

I've attached the slide decks and the demo content for both talks to this post so that anyone who's interested can have a look at the slides or play around with the demos.

I hope those of you who attended today enjoyed the talk and learned more about the Toolkit - it was great to have an opportunity to spend time with you!

[AspNetConnections200703-AMS305-AMS304-AjaxControlToolkit.zip]

Computing the size of your boat [Sample code to help analyze storage space requirements]

Yesterday I mentioned a quick C# program I wrote to help analyze storage space requirements. There was some interest in how that program worked, so I'm posting the complete source code for anyone to use.

using System;
using System.Collections.Generic;
using System.IO;

class SizeOfFilesCreatedOnDate
{
    
private const string outputFileName = "SizeOfFilesCreatedOnDate.csv";

    
static void Main(string[] args)
    {
        
// Create a dictionary to hold the date/size pairs (sorted for subsequent output)
        SortedDictionary<DateTime, long> sizeOfFilesCreatedOnDate = new SortedDictionary<DateTime, long>();

        
// Tally the contents of each specified directory
        // * If no command-line argument was given, default to the current directory
        if (0 == args.Length)
        {
            args =
new string[] { Environment.CurrentDirectory };
        }
        
foreach (string directory in args)
        {
            AddDirectoryContents(directory,
ref sizeOfFilesCreatedOnDate);
        }

        
// Output all date/size pairs to a CSV file in the current directory
        using (StreamWriter writer = File.CreateText(outputFileName))
        {
            writer.WriteLine(
"Date,Size,Cumulative");
            
long cumulative = 0;
            
foreach (DateTime date in sizeOfFilesCreatedOnDate.Keys)
            {
                
long size = sizeOfFilesCreatedOnDate[date];
                cumulative += size;
                writer.WriteLine(
"{0},{1},{2}", date.ToShortDateString(), size, cumulative);
            }
        }
        
Console.WriteLine("Output: {0}", outputFileName);
    }

    
private static void AddDirectoryContents(string directory, ref SortedDictionary<DateTime, long> sizeOfFilesCreatedOnDate)
    {
        
// Display status
        Console.WriteLine("Scanning: {0}", directory);

        
// Tally each child file in the parent directory
        foreach (string file in Directory.GetFiles(directory))
        {
            
// Get a FileInfo for the file
            FileInfo fileInfo = new FileInfo(file);

            
// Get the creation time of the file
            // * If last write < creation, then the file was moved at least once; use the earlier date
            // * The difference between local/UTC (~hours) is unimportant at this scale (~years); use local
            DateTime date = fileInfo.CreationTime.Date;
            
if (fileInfo.LastWriteTime.Date < date)
            {
                date = fileInfo.LastWriteTime.Date;
            }

            
// Update the relevant date/size pair
            long size;
            
if (!sizeOfFilesCreatedOnDate.TryGetValue(date, out size))
            {
                size = 0;
            }
            sizeOfFilesCreatedOnDate[date] = size + fileInfo.Length;
        }

        
// Recursively tally each child directory in the parent directory
        foreach (string childDirectory in Directory.GetDirectories(directory))
        {
            AddDirectoryContents(childDirectory,
ref sizeOfFilesCreatedOnDate);
        }
    }
}

Notes:

  • I wrote this code for a simple one-time purpose, so there's no fancy/friendly user interface.
  • There's also no error-checking. In particular, if it bumps into a directory/file that it doesn't have permission to access, the resulting UnauthorizedAccessException will bubble up and terminate the process. (While this is unlikely to occur when using the program for its intended purpose of examining your data files, it is pretty likely to occur if playing around and pointing it at C:\.)
  • Other than adding comments and support for specifying multiple directories on the command-line, this is the same code I used to generate my chart.
  • The code for handling last write time being earlier than creation time was something I discovered a need for experimentally when I noticed that considering only creation time reported that none of my files were older than a couple of years. Apparently when I moved stuff around a couple of years ago, the copy to my current drive preserved the file's last write time, but reset its creation time (perhaps because of the FAT->NTFS transition).

Enjoy!

Tags: Technical

"You're gonna need a bigger boat." [A brief look at data storage requirements in today's world]

I've previously blogged about my data storage/backup strategy. Briefly, I've got one big drive in my home server that stores all the data my family cares about: mostly music, pictures, and videos (with a little bit of other stuff for good measure). To protect the data, I've got another equally big external drive that I connect occasionally and use for backups by simply mirroring the content of the internal drive.

As things stand today, the internal drive is 320GB and the external drive is 300GB, but I've hit the wall and am almost out of space to add new files. Looking at hard drive prices these days, the sweet spot (measured in $/GB) seems to be with 500GB drives at about $140 (PATA or SATA). Any smaller than that and the delta from 300GB isn't enough to be interesting - any larger than that and the cost really goes up.

I was already prepared to buy a new drive every year or so to allow for growth, so I was curious if getting a 500GB drive now would do the trick. I wrote a quick program to look at every file I backup and tally up the size according to the date the file was created. The C# program walks the whole directory tree, sums the sizes by date, and writes out a simple CSV file with the results. The idea here is to chart the rate at which I'm adding data in order to predict when I'd run out of space next. (Yes, it's easy to come up with more sophisticated heuristics, but this is really just a back-of-the-envelope calculation and doesn't need to be perfect to be meaningful.)

Last night I opened the CSV file in Excel and charted the data. The resulting chart looks like this:

Data Storage Space (GB)

The blue line represents the cumulative size of the data I had at each point in time (horizontal axis) measured in GB (vertical axis) - you can see that I'm just above 300GB today. The red line is Excel's exponential trend line for the same data - it matches the blue line almost perfectly, so it seems pretty safe to say that my data storage needs are increasing exponentially. I was kind of afraid of that, because it means the 500GB drives I've been considering are likely to fill up within the next 8 months!

Clearly, I need to be prepared to spend more on hard drives than I'd initially planned to - or else I'm going to need to significantly change how I do things. I've got some ideas I'm still considering, but charting this data was a good wake-up call that drive capacity isn't increasing as rapidly as I might like. :)

I think that data storage and backup are issues that will affect all of us pretty soon (if they're not already). Backing up to DVDs doesn't scale well once you need more than 10 or so DVDs, and backing up over the network just doesn't seem practical when you're talking about numbers this large. Even ignoring the need to backup, simply storing all the data you have is rapidly becoming an issue. With downloadable HD movie/TV content becoming popular, high megapixel still/video cameras being commonplace, and fast Internet connections becoming the norm, it seems to me that content is outpacing storage right now.

Here's hoping for a quantum leap in storage technology!

Updated on 2007/03/14: I've just posted the source code for the program I wrote to gather this data.

Tags: Technical

Lost (Sk)in Translation [AJAX Control Toolkit update!]

A short while ago we made available the 10301 release of the AJAX Control Toolkit. With this release, we managed to add some great core functionality, a couple of new controls, and a bunch of bug fixes for popular issues (as identified by our user community in the support forum and online issue tracker).

The 10301 release includes two new controls:

  • ListSearch (by contributor Damian Mehers) - A handy enhancement to ListBox/DropDownList controls that allows the user to select items by typing the first few characters
  • SlideShow (by our own Kirti) - A visually pleasing slide show of automatically sized images and captions with optional automatic looping or manual control

We also managed to add three pieces of core functionality that users have been asking for:

  • Localization support - The Toolkit now has an infrastructure for localizing the text in JavaScript files using the standard ASP.NET/AJAX support for resource files. There are placeholder files for the following 14 languages: Arabic, German, English, Spanish, French, Hebrew, Hindi, Italian, Japanese, Korean, Portuguese, Russian, Chinese (Simplified), and Chinese (Traditional). Complete localization of all strings hasn't been done yet, but our most popular request by far is for the string "Today:" at the bottom of the Calendar's popup - and that has already been localized to all of the above languages. Just set your system/browser's language settings to one of the supported languages and visit the Calendar sample page for a demonstration.
  • JavaScript comment/whitespace stripping - People are always interested in keeping the download size of their pages as low as possible, and the Toolkit goes the extra mile to help. When compiled in "Release" mode (as the official releases on CodePlex always are), all of the JavaScript files in the Toolkit automatically have all comments and unnecessary whitespace removed. Ted, the author of this functionality, was careful to adhere to the ECMA-262 ECMAScript Language Specification, so the modifications are both safe and effective.
  • ASP.NET Theme/Skin support - Central control is usually best, so it's nice to be able to use ASP.NET's theme/skin support to specify properties for controls across an entire web site in one central location. Toolkit controls didn't used to be skinnable (i.e., support the SkinID property) but now they are, so go ahead and start skinning your site. In fact, we used this new ability to style the CollapsiblePanels that we use for descriptions/properties/known issues on every sample page.

And, with the help of our contributors, we fixed a bunch of bugs along the way...

We hope you like the new release!!

Recall that you can sample any of the controls right now (no install required). You can also browse the project web site, download the latest Toolkit, and start creating your own controls and/or contributing to the project!

If you have any feedback, please share it with us on the support forum (or email me)!