<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>HD DVD / Randomness...</title><link>http://blogs.msdn.com/ptorr/default.aspx</link><description>Peter Torr's blog on HD DVD, JScript, the Pet Shop Boys, and anything else he feels like blogging.</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>What Now?</title><link>http://blogs.msdn.com/ptorr/archive/2008/02/20/what-now.aspx</link><pubDate>Wed, 20 Feb 2008 22:18:46 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7822373</guid><dc:creator>ptorr</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/ptorr/comments/7822373.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ptorr/commentrss.aspx?PostID=7822373</wfw:commentRss><wfw:comment>http://blogs.msdn.com/ptorr/rsscomments.aspx?PostID=7822373</wfw:comment><description>&lt;p&gt;I have had some readers ask what is to become of this blog. Well, it started out discussing &lt;a href="http://blogs.msdn.com/ptorr/archive/2003/09/09/56181.aspx"&gt;Office Development&lt;/a&gt;, then it covered &lt;a href="http://blogs.msdn.com/ptorr/archive/2005/02/22/GuerillaThreatModelling.aspx"&gt;Threat Modelling&lt;/a&gt;, and most recently it has been about &lt;a href="http://blogs.msdn.com/ptorr/archive/2007/05/16/a-game-of-chance-that-pirates-like-to-play.aspx"&gt;HDi&lt;/a&gt;. There have been several posts about the &lt;a href="http://blogs.msdn.com/ptorr/archive/2006/04/11/573572.aspx"&gt;Pet Shop Boys&lt;/a&gt; and then there was &lt;a href="http://blogs.msdn.com/ptorr/archive/2004/12/20/327511.aspx"&gt;this little post&lt;/a&gt;, too. That's the cool thing about Microsoft; you work on one thing for a while, and if it doesn't work out (or if you decide you want to try something new) then you just go do it.
&lt;/p&gt;&lt;p&gt;One thing's for sure – I'm not about to start posting about BD-J authoring :-)
&lt;/p&gt;&lt;p&gt;I still have a few &lt;a href="http://blogs.msdn.com/ptorr/archive/2008/01/29/fun-friends-for-functions.aspx"&gt;script-based posts&lt;/a&gt; to finish, but after that I don't know how often I will update the blog because most likely I will be working on the Next Big Thing, and most likely that won't be public (and thus not blog-able). Anyway, thanks for reading and if you choose to stick around then maybe I'll post something cool again in a few months...
&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.hddvdforever.com/"&gt;http://www.hddvdforever.com/&lt;/a&gt;
	&lt;/p&gt;&lt;p&gt;Peter.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7822373" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ptorr/archive/tags/Randomness/default.aspx">Randomness</category><category domain="http://blogs.msdn.com/ptorr/archive/tags/HD+DVD/default.aspx">HD DVD</category><category domain="http://blogs.msdn.com/ptorr/archive/tags/iHD/default.aspx">iHD</category><category domain="http://blogs.msdn.com/ptorr/archive/tags/HDi/default.aspx">HDi</category></item><item><title>Fun Friends for Functions, Part 2: Handling Exceptions</title><link>http://blogs.msdn.com/ptorr/archive/2008/02/01/fun-friends-for-functions-part-2-handling-exceptions.aspx</link><pubDate>Sat, 02 Feb 2008 04:24:40 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7380450</guid><dc:creator>ptorr</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/ptorr/comments/7380450.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ptorr/commentrss.aspx?PostID=7380450</wfw:commentRss><wfw:comment>http://blogs.msdn.com/ptorr/rsscomments.aspx?PostID=7380450</wfw:comment><description>&lt;p&gt;Previously we looked at how you can &lt;a href="http://blogs.msdn.com/ptorr/archive/2008/01/29/fun-friends-for-functions.aspx"&gt;bind a function to a set of arguments&lt;/a&gt; and then call the resultant function at some time in the future. This technique is very powerful, but as-is it is a ticking bomb. As Amy points out in her &lt;a href="http://blogs.msdn.com/amyd/archive/2007/12/07/exception-handling.aspx"&gt;blog post on exception handling&lt;/a&gt;, you always need to be prepared to handle an exception in your code. Failure to catch an exception usually leads to playback stopping and an error diagnostic from your player.
&lt;/p&gt;&lt;p&gt;The trouble is that when you start using bound functions, you don't always have an easy way to deal with exceptions. Typically, a bound function is used as part of an asynchronous callback, and in those cases you don't have any functions further up the stack to save you from unhandled errors. Simple, you might think, I'll just wrap the contents of my function in a try-catch and be done with it.
&lt;/p&gt;&lt;p&gt;Not so fast.
&lt;/p&gt;&lt;p&gt;Let's look at the example function we were using in the previous blog post:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;
 &lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// function to set a backgroundImage&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; SetBackgroundImage(markupId, url)&lt;br/&gt;{&lt;br/&gt;  document[markupId].style.backgroundImage = url;&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;This could throw for several reasons – for example, an element with the &lt;strong&gt;markupId&lt;/strong&gt; doesn't exist, or &lt;strong&gt;url&lt;/strong&gt; isn't a correctly-formatted property value. Simply wrapping this up in a try-catch would result in something like this:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;
 &lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// function to set a backgroundImage&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; SetBackgroundImage(markupId, url)&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:blue"&gt;try&lt;br/&gt;&lt;/span&gt;  {&lt;br/&gt;    document[markupId].style.backgroundImage = url;&lt;br/&gt;  }&lt;br/&gt;  &lt;span style="color:blue"&gt;catch&lt;/span&gt;(ex)&lt;br/&gt;  {&lt;br/&gt;    &lt;span style="color:green"&gt;// What do we do here?!?&lt;br/&gt;&lt;/span&gt;  }&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;But there's a problem – what do we do when we catch the exception? I don't know. And that's a key thing about exception handling:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;strong&gt;Functions should only handle exceptions if they are &lt;em&gt;actually prepared to deal with them&lt;/em&gt;. If a function doesn't know what to do in an error condition, it should let its caller figure it out. The exception [groan] to this rule is that your top-level code should &lt;em&gt;always&lt;/em&gt; swallow exceptions (unless of course things are so out of whack that you think the player should stop immediately).
&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;In this case, the &lt;strong&gt;SetBackgroundImage&lt;/strong&gt; function has no idea what a failure means. It might be perfectly OK if the background image can't be set correctly, or it could be totally disastrous. It all depends on the context, so the &lt;strong&gt;SetBackgroundImage&lt;/strong&gt; function should remain silent on the topic of exceptions and let the calling function figure out what (if anything) to do with them.
&lt;/p&gt;&lt;p&gt;In our particular case, let's say that the exception is benign; we are simply updating some eye-candy graphics and it doesn't matter if they fail to appear. So then: maybe we should write a wrapper function, &lt;strong&gt;SafeSetBackgroundImage&lt;/strong&gt;, that does this for us?
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;
 &lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// function to set a backgroundImage, ignoring exceptions&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; SafeSetBackgroundImage(markupId, url)&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:blue"&gt;try&lt;br/&gt;&lt;/span&gt;  {&lt;br/&gt;    SetBackgroundImage(markupId, url);&lt;br/&gt;  }&lt;br/&gt;  &lt;span style="color:blue"&gt;catch&lt;/span&gt;(ex) { }&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;I actually like to use this approach if I am going to be calling the 'Safe' version in a lot of different places, but if it is only in one or two places that seems like too much overhead to someone lazy like me. Anytime you update the parameter list of the wrapped function, you have to update the wrappers, too. It can also hide the intent of your code by sprinkling endless wrapper functions all over the place, and this also has the productivity-reducing effect of polluting IntelliSense with unnecessary function names. Instead, we can use the same kind of nested-function trick we used in the argument-binding case to get a "safe" version of any function:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;
 &lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// return a version of a function that is wrapped in try-catch&lt;br/&gt;// you can optionally provide an errorFunc, which will be&lt;br/&gt;// called with the 'tag' parameter in case of an exception&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; Function_WrapInTryCatch(errorFunc, tag)&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:green"&gt;// stash the target function&lt;br/&gt;&lt;/span&gt;  &lt;span style="color:blue"&gt;var&lt;/span&gt; func = &lt;span style="color:blue"&gt;this&lt;/span&gt;;
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  &lt;span style="color:green"&gt;// return the nested function&lt;br/&gt;&lt;/span&gt;  &lt;span style="color:blue"&gt;return&lt;/span&gt; wrappedFunction;
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  &lt;span style="color:blue"&gt;function&lt;/span&gt; wrappedFunction()&lt;br/&gt;  {&lt;br/&gt;    &lt;span style="color:green"&gt;// wrap the original function in a try-catch&lt;br/&gt;&lt;/span&gt;    &lt;span style="color:blue"&gt;try&lt;br/&gt;&lt;/span&gt;    {&lt;br/&gt;      func();&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;catch&lt;/span&gt; (ex)&lt;br/&gt;    {&lt;br/&gt;      &lt;span style="color:green"&gt;// call the errorFunc if it was provided&lt;br/&gt;&lt;/span&gt;      &lt;span style="color:green"&gt;// note this MUST be resilient to errors; if it throws&lt;br/&gt;&lt;/span&gt;      &lt;span style="color:green"&gt;// then it is game over.&lt;br/&gt;&lt;/span&gt;      &lt;span style="color:blue"&gt;if&lt;/span&gt; (&lt;span style="color:blue"&gt;typeof&lt;/span&gt; errorFunc == &lt;span style="color:#a31515"&gt;"function"&lt;/span&gt;)&lt;br/&gt;      {&lt;br/&gt;        errorFunc(ex, tag);&lt;br/&gt;      }&lt;br/&gt;    }&lt;br/&gt;  }&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;Function.prototype.WrapInTryCatch = Function_WrapInTryCatch;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;In this example, we also allow the caller of the &lt;strong&gt;WrapInTryCatch&lt;/strong&gt; function to provide an optional error-handling function that will be called if an error occurs. This allows you to do things like channel all your async exceptions to the same error handling function, which can figure out what to do based on the value of the &lt;strong&gt;tag&lt;/strong&gt; parameter. Now we can re-write the last couple of lines of the example as:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;
 &lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// Call the download function, passing in the set-image function as the callback handler&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;var&lt;/span&gt; setBackgroundHandler = SetBackgroundImage.BindToArguments(&lt;span style="color:#a31515"&gt;"button1"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;"file:///filecache/bar.png"&lt;/span&gt;);&lt;br/&gt;&lt;span style="color:blue"&gt;var&lt;/span&gt; wrappedHandler = setBackgroundHandler.WrapInTryCatch();&lt;br/&gt;DownloadFile(&lt;span style="color:#a31515"&gt;"http://foo/bar.png"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;"file:///filecache/bar.png"&lt;/span&gt;, wrappedHandler);
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;This helper has the same limitations as the &lt;strong&gt;BindToArguments&lt;/strong&gt; function (specifically: you can't pass any arguments to the returned function, and any tracing information is lost if 'errorFunc' is called) but this is also a solvable problem.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7380450" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ptorr/archive/tags/Script/default.aspx">Script</category><category domain="http://blogs.msdn.com/ptorr/archive/tags/iHD/default.aspx">iHD</category><category domain="http://blogs.msdn.com/ptorr/archive/tags/HDi/default.aspx">HDi</category></item><item><title>Why the ‘arguments’ object is bad, Exhibit #3,745</title><link>http://blogs.msdn.com/ptorr/archive/2008/01/30/why-the-arguments-object-is-bad-exhibit-3-745.aspx</link><pubDate>Thu, 31 Jan 2008 00:46:52 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7334659</guid><dc:creator>ptorr</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/ptorr/comments/7334659.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ptorr/commentrss.aspx?PostID=7334659</wfw:commentRss><wfw:comment>http://blogs.msdn.com/ptorr/rsscomments.aspx?PostID=7334659</wfw:comment><description>&lt;p&gt;Having just written a post with an &lt;a href="http://blogs.msdn.com/ptorr/archive/2008/01/29/fun-friends-for-functions.aspx"&gt;example of how to use the arguments object&lt;/a&gt;, you might question my choice of title for this blog post. In my not-so-humble opinion, the 'arguments' object in ECMAScript is only useful for one thing:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;strong&gt;The 'arguments' object should only be used by infrastructure functions that simply perform book-keeping on behalf of other functions. Any function that actually operates on its arguments in a meaningful way should never access the 'arguments' object. 
&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;The reason for this is plain and simple: code should be easy to &lt;em&gt;read&lt;/em&gt;, easy to &lt;em&gt;debug&lt;/em&gt;, and easy to &lt;em&gt;maintain&lt;/em&gt;. Saving yourself a small amount of effort while &lt;em&gt;writing&lt;/em&gt; code is a very bad trade-off if it negatively impacts these other three important tasks. Using the 'arguments' object in any normal function might save you a few keystrokes in the short-term, but will come back to bite you later on.
&lt;/p&gt;&lt;p&gt;The most obvious problem with the arguments object is this: You have some code you wrote a few [days|weeks|years] ago and now you have to go and update it. You see some function calls like this in source code:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;
 &lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;SomeBadFunction(42);&lt;br/&gt;&lt;span style="color:green"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;SomeBadFunction(i, current);&lt;br/&gt;&lt;span style="color:green"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;SomeBadFunction(next, data, OtherFunction(), moreData);&lt;br/&gt;&lt;span style="color:green"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;You think the problem might be related to one of the parameters being passed to &lt;strong&gt;SomeBadFunction&lt;/strong&gt;, so you decide you need to check it out:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;
 &lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; SomeBadFunction()&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:green"&gt;// 200 lines of code&lt;br/&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;Oh dear. The definition of &lt;strong&gt;SomeBadFunction&lt;/strong&gt; gives us &lt;em&gt;absolutely no idea&lt;/em&gt; how many parameters it expects, what order they should be in, nor what values they might represent. &lt;em&gt;Maybe&lt;/em&gt; there's a comment at the top of the function that explains what you should pass it, but we all know that comments get out of date very quickly and the code is the only real way to know what is going on. So now you have to trawl through several hundred lines of code, trying to reverse-engineer what kind of parameters the function expects. This could take a long time, and you might get it wrong.
&lt;/p&gt;&lt;p&gt;Let's imagine that the real intent of &lt;strong&gt;SomeBadFunction&lt;/strong&gt; is to update an internal table. The first parameter is the index of the item in the table to update, and the second parameter is the value to place in the table. The function supports rudimentary format strings (like &lt;strong&gt;printf()&lt;/strong&gt; in C) and so if the value contains a format-specifier like "%d" or "%s" then the remaining parameters are used to fill in the blanks. Finally, if the value is omitted then the table entry is removed.
&lt;/p&gt;&lt;p&gt;In this case, I would define the function something like this:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;
 &lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; SomeBadFunction(index, value, formatArgs)&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:green"&gt;// probably fewer than 200 lines of code&lt;br/&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;Now it is clear that &lt;strong&gt;SomeBadFunction&lt;/strong&gt; expects three arguments, the first should probably be a number, the second should be some generic value, and the third should be an array of values (by using the naming convention &lt;strong&gt;...Args&lt;/strong&gt;; you could also call it &lt;strong&gt;formatArgArray&lt;/strong&gt; or &lt;strong&gt;paramarray&lt;/strong&gt; or &lt;strong&gt;varargs&lt;/strong&gt; or something else if you feel that is clearer). 
&lt;/p&gt;&lt;p&gt;ECMAScript already allows for omitting function arguments, and code is typically written to have some "obvious" behaviour if parameters end up being &lt;strong&gt;undefined&lt;/strong&gt;, so simply dropping &lt;strong&gt;value&lt;/strong&gt; or &lt;strong&gt;formatArgs&lt;/strong&gt; from a function call is quite OK. Now the only thing you need to change when you call the function is that if – &lt;em&gt;if&lt;/em&gt; – you want to use the special format-string ability of &lt;strong&gt;SomeBadFunction&lt;/strong&gt;, you simply encase the trailing arguments in square brackets to put them in an Array:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;
 &lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;SomeBadFunction(next, data, [OtherFunction(), moreData]);
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;Anyway, I promised you an exhibit of why 'arguments' is bad – a bona-fide bug in ECMAScript, not just the rambling opinions of some Microsoft fuddy-duddy. Take this code:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;
 &lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; foo(x, y)&lt;br/&gt;{&lt;br/&gt;  print(&lt;span style="color:#a31515"&gt;"x: "&lt;/span&gt; + x + &lt;span style="color:#a31515"&gt;", y: "&lt;/span&gt; + y);&lt;br/&gt;  Array.prototype.shift.call(arguments);&lt;br/&gt;  print(&lt;span style="color:#a31515"&gt;"x: "&lt;/span&gt; + x + &lt;span style="color:#a31515"&gt;", y: "&lt;/span&gt; + y);&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;foo(42, 123);
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;What do you expect&lt;em&gt;
		&lt;/em&gt;it to display? Don't ruin the fun by running it and posting the &lt;em&gt;actual&lt;/em&gt; answer – just post what you &lt;em&gt;think&lt;/em&gt; it is.
&lt;/p&gt;&lt;p&gt;I say this is a bug in ECMAScript – rather than a bug in JScript – because section 10.1.8 of the ECMA 262 spec doesn't &lt;em&gt;completely&lt;/em&gt; define how the arguments object interacts with the parameters of the function, and so you get some strange results. Note that both IE and Firefox give you the same result (replace 'print' with 'alert') but I doubt both companies independently came up with the same unexcpected result. I don't know if this is a case of IE being bug-compatible with the original Netscape Navigator code, or Firefox being bug-compatible with IE code, or a bit of both. I wasn't around when this was happening :-)&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7334659" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ptorr/archive/tags/Script/default.aspx">Script</category></item><item><title>Fun Friends For Functions</title><link>http://blogs.msdn.com/ptorr/archive/2008/01/29/fun-friends-for-functions.aspx</link><pubDate>Wed, 30 Jan 2008 03:45:34 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7315751</guid><dc:creator>ptorr</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/ptorr/comments/7315751.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ptorr/commentrss.aspx?PostID=7315751</wfw:commentRss><wfw:comment>http://blogs.msdn.com/ptorr/rsscomments.aspx?PostID=7315751</wfw:comment><description>&lt;p&gt;And now for a more techy post. In ECMAScript, functions are considered first-class objects. "What," you might ask, "differentiates a 'first-class' object from a merely 'economy-class' object?" Well, the main thing is that functions in ECMAScript are treated just like any other type of data (strings, numbers, arrays, etc.) in that they can be assigned to variables, they can be passed as function arguments, and they can have properties and methods of their own. They also have a prototype object, just like all other ECMAScript objects. The upshot of this is that you can do fun things with functions in ECMAScript that you can't do in other languages such as C or Java.
&lt;/p&gt;&lt;p&gt;In this entry I will introduce four types of "helper" functions that are ideally suited to HDi development. They are:
&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Binding a function to a set of arguments and / or a 'this' object
&lt;/li&gt;&lt;li&gt;Wrapping an existing function in an exception handler
&lt;/li&gt;&lt;li&gt;Chaining function calls together one after the other
&lt;/li&gt;&lt;li&gt;Calling a function after a specified period of time
&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In all cases, you write the actual function (the one that does the interesting work) just as you normally would, but when it comes time to call that function you do something funky with it to make some magic happen. Exactly why you might want to do this will become clearer soon, but it mostly comes down to how you write event handlers and callbacks.
&lt;/p&gt;&lt;p&gt;A common theme in this post will be that you want to &lt;a href="http://blogs.msdn.com/ptorr/archive/2007/08/29/using-timers-effectively-in-hdi.aspx"&gt;avoid closures&lt;/a&gt; as much as possible, and using these helpers should get you a long way to doing that (even though these helper functions rely on closures, they do so in a "safe" manner). And although there are various ad-hoc ways to accomplish the same tasks, generally these require writing specialised wrapper functions or following ugly coding practices (which I might blog about in the future) when what I would prefer to focus on is writing highly readable, highly re-usable code and utilising some clever, general-purpose helper functions to take care of all the tricky dirty work.
&lt;/p&gt;&lt;h3&gt;Binding to arguments
&lt;/h3&gt;&lt;p&gt;Many operations in HDi use a callback function to notify you when a specific task is completed (such as a File I/O operation or an event handler). Oftentimes you will want to associate more information with your callback than the HDi API actually allows for, and there are a couple of ways to accomplish this. But first, an example: 
&lt;/p&gt;&lt;p&gt;Say you have an application where you want to dynamically download some images from the network and display them inside a markup page. The basic code you want to write is probably like this (the code is simplified for clarity; obviously there is some additional code to convert the &lt;strong&gt;onStateChange&lt;/strong&gt; callback into a single "the download is complete" call, etc.):
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;
 &lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// function to download an image&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; DownloadImage(src, dest)&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:blue"&gt;var&lt;/span&gt; httpClient = Network.createHttpClient(src, dest);&lt;br/&gt;  httpClient.onStateChange = SetBackgroundImage;&lt;br/&gt;  httpClient.send();&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// function to set a backgroundImage&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; SetBackgroundImage(markupId, url)&lt;br/&gt;{&lt;br/&gt;  document[markupId].style.backgroundImage = url;&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// call the download function... but what next?&lt;br/&gt;&lt;/span&gt;DownloadImage(&lt;span style="color:#a31515"&gt;"http://foo/bar.png"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;"file:///filecache/bar.png"&lt;/span&gt;);
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;Note that both functions have been written to be "highly readable, highly re-usable" and do one thing in a very straight-forward manner. The problem, of course, is that this code won't work because there is no way for the callback to &lt;strong&gt;SetBackgroundImage&lt;/strong&gt; to communicate what &lt;strong&gt;markupId&lt;/strong&gt; or the final download &lt;strong&gt;url&lt;/strong&gt; is supposed to be. 
&lt;/p&gt;&lt;p&gt;One common way of solving this problem is to use a nested function, like this:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;
 &lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// function to download an image and set it as the background URL&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; DownloadBackgroundImage(src, dest, markupId)&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:blue"&gt;var&lt;/span&gt; httpClient = Network.createHttpClient(src, dest);&lt;br/&gt;  httpClient.onStateChange = SetBackgroundImage;&lt;br/&gt;  httpClient.send();
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  &lt;span style="color:green"&gt;// nested function to set a backgroundImage&lt;br/&gt;&lt;/span&gt;  &lt;span style="color:blue"&gt;function&lt;/span&gt; SetBackgroundImage()&lt;br/&gt;  {&lt;br/&gt;    document[markupId].style.backgroundImage = dest;
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;    &lt;span style="color:green"&gt;// Clean up the memory&lt;br/&gt;&lt;/span&gt;    httpClient = &lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;  }&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// call the download function and update the element 'button1'&lt;br/&gt;&lt;/span&gt;DownloadBackgroundImage(&lt;span style="color:#a31515"&gt;"http://foo/bar.png"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;"file:///filecache/bar.png"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;"button1"&lt;/span&gt;);
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;Note that even though we've done work to ensure the closure won't memory leak memory, there is still at big problem in that neither the download function nor the background setting function are generic any more. If you want to (eg) download an XML file, or if you want to set the backgroundImage to a file on persistent storage, you will need to either add some more hacks to this function (making it less readable and less maintainable) or you will need to duplicate the code into a similar-but-not-entirely-the-same function.
&lt;/p&gt;&lt;p&gt;The solution I prefer is to use the fact that functions are first-class objects and solve this problem using "argument binding." In this case, the code would be re-written as follows:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;
 &lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// function to download a file and then call 'handler' when it is done&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; DownloadFile(src, dest, handler)&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:blue"&gt;var&lt;/span&gt; httpClient = Network.createHttpClient(src, dest);&lt;br/&gt;  httpClient.onStateChange = handler;&lt;br/&gt;  httpClient.send();&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// function to set a backgroundImage&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; SetBackgroundImage(markupId, url)&lt;br/&gt;{&lt;br/&gt;  document[markupId].style.backgroundImage = url;&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// Call the download function, passing in the set-image function as the callback handler&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;var&lt;/span&gt; setBackgroundHandler = SetBackgroundImage.BindToArguments(&lt;span style="color:#a31515"&gt;"button1"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;"file:///filecache/bar.png"&lt;/span&gt;);&lt;br/&gt;DownloadFile(&lt;span style="color:#a31515"&gt;"http://foo/bar.png"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;"file:///filecache/bar.png"&lt;/span&gt;, setBackgroundHandler);
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;Now both the download function and the set-image function are still written in a clear, simple, re-usable fashion, but we can easily chain them together to get the desired result. Even the call that makes this possible (the &lt;strong&gt;BindToArguments&lt;/strong&gt; call) is straight-forward and understandable. All that is missing is the magic &lt;strong&gt;BindToArguments&lt;/strong&gt; helper function... which looks like this:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;
 &lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// helper function to return a copy of the target function, but&lt;br/&gt;// bound to the original arguments&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; Function_BindToArguments()&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:green"&gt;// store a reference to the target function and its arguments&lt;br/&gt;&lt;/span&gt;  &lt;span style="color:blue"&gt;var&lt;/span&gt; storedFunction = &lt;span style="color:blue"&gt;this&lt;/span&gt;;&lt;br/&gt;  &lt;span style="color:blue"&gt;var&lt;/span&gt; storedArguments = arguments;
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  &lt;span style="color:green"&gt;// return the nested function&lt;br/&gt;&lt;/span&gt;  &lt;span style="color:blue"&gt;return&lt;/span&gt; boundFunction;
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  &lt;span style="color:green"&gt;// nested function simply invokes the stashed values&lt;br/&gt;&lt;/span&gt;  &lt;span style="color:blue"&gt;function&lt;/span&gt; boundFunction()&lt;br/&gt;  {&lt;br/&gt;    storedFunction.apply(&lt;span style="color:blue"&gt;null&lt;/span&gt;, storedArguments);&lt;br/&gt;  }&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// make the helper available to all functions&lt;br/&gt;&lt;/span&gt;Function.prototype.BindToArguments = Function_BindToArguments;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;As noted in the comments, this helper function simply stores a reference to the "target" function and the arguments that are passed to the &lt;strong&gt;BindToArguments&lt;/strong&gt; call. Then it returns a nested function, which when called will invoke the stored function (&lt;strong&gt;SetBackgroundImage&lt;/strong&gt;) with the stored arguments (&lt;strong&gt;"button1"&lt;/strong&gt; and &lt;strong&gt;"file:///filecache/bar.png"&lt;/strong&gt;). Note that the &lt;strong&gt;apply&lt;/strong&gt; function is a built-in function of ECMAScript Function objects that invokes a given function with the specified 'this' object and arguments array.
&lt;/p&gt;&lt;p&gt;This is the most basic form of a "binding" helper, and the resultant function is one that has no 'this' object and that cannot take any arguments of its own. It also can't participate in a typical &lt;a href="http://blogs.msdn.com/ptorr/archive/2007/06/27/helpful-tracing-routines.aspx"&gt;logging infrastructure&lt;/a&gt; because much of the required metadata (original function name, number of expected arguments, etc.) is missing. The good news is that all this can be added with the help of more code, and hopefully that's something I'll be posting soon. 
&lt;/p&gt;&lt;p&gt;As usual, this is longer (and took longer) to write, so I'll have to save the other "friends" for later. The depressing thing is that actually writing the code is the easy part (and it's all done already); it's wrapping it all up in a post and explaining how things work that take forever!&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7315751" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ptorr/archive/tags/Script/default.aspx">Script</category><category domain="http://blogs.msdn.com/ptorr/archive/tags/iHD/default.aspx">iHD</category><category domain="http://blogs.msdn.com/ptorr/archive/tags/HDi/default.aspx">HDi</category></item><item><title>A Concert with PowerPoint Slides?</title><link>http://blogs.msdn.com/ptorr/archive/2008/01/29/a-concert-with-powerpoint-slides.aspx</link><pubDate>Tue, 29 Jan 2008 20:36:56 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7309651</guid><dc:creator>ptorr</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/ptorr/comments/7309651.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ptorr/commentrss.aspx?PostID=7309651</wfw:commentRss><wfw:comment>http://blogs.msdn.com/ptorr/rsscomments.aspx?PostID=7309651</wfw:comment><description>&lt;p&gt;As you may know, &lt;a href="http://www.howardjones.com/"&gt;Howard Jones&lt;/a&gt; played an acoustic show in Seattle last night with &lt;a href="http://www.dtox.co.uk/itch.htm"&gt;Robin Boult&lt;/a&gt; on guitar. The performance was fantastic, and the venue (&lt;a href="http://www.thetripledoor.net/"&gt;The Triple Door&lt;/a&gt;) was actually quite nice with a limited menu coming from the kitchens of &lt;a href="http://www.wildginger.net/"&gt;Wild Ginger&lt;/a&gt;. (Although I enjoyed the food, I am not really a fan of having the waiters walk past every 5 minutes, or of all the clanging of silverware and glassware as people finish their dessert... but I digress). 
&lt;/p&gt;&lt;p&gt;Anyway, the reason for this blog post is that before many of the songs, Howard gave a little bit of background about the song – what it was about, how it was written, previous live performances, etc. – and at one point joked that he needed a PowerPoint deck to help tell his story. And this got me thinking about what we are doing with interactivity in HD DVD with HDi: although the movie (or TV show or concert performance) is central to any home viewing experience, it is really the "extra" stuff that sets HD DVD away from current DVD or broadcast TV. 
&lt;/p&gt;&lt;p&gt;A High Definition picture is nice, and lossless surround-sound is pretty sweet too, but as a &lt;a href="http://www.imdb.com/name/nm2121192/"&gt;filmmaker myself&lt;/a&gt; I know that there is always more to the story than you can tell in the movie (TV show; song; etc.) itself. And as a movie lover, I know there is often more that I want to know about the story than is available in the movie (...) itself. Standard DVD has the usual staple of vignettes (deleted scenes, making-of documentaries, trailers) but for various reasons they tend to get skipped by many viewers. 
&lt;/p&gt;&lt;p&gt;You might watch a 30 minute documentary in the hopes of learning more about (eg) the location a movie was shot, only to be disappointed at the end when no information is made available. And since DVD is "set in stone" once it goes to the replicator, there's no way for you to ask them to add that information later. Or perhaps a DVD extra provides a filmography or a gossip about the actors in the movie, but by the time the disc hits your DVD player it is woefully out of date. Problems such as these leave many people underwhelmed by DVD extras and lead to attitude that they're of little value... even though if you actually sit down and talk to those same people, many of them really do want more out of their disc-watching experiences, especially for content they care about (favourite movies, TV shows, or music artists) – and these are exactly the kind of discs they would buy!
&lt;/p&gt;&lt;p&gt;With technologies such as HDi in HD DVD, the producers can add all manner of information to the disc and let "you control" which bits of information you to see, and when. No more sitting through hours of bonus material in the hope that &lt;em&gt;maybe&lt;/em&gt; you'll get an out-dated snippet of what you're interested in. With true interactivity, you can go straight to the information you want and can be confident that it is up-to-date via connections to the internet. And if the information you want isn't there, why not send feedback directly to the producers that you want to see it added in the future?
&lt;/p&gt;&lt;p&gt;On HD DVD, Howard Jones could have his PowerPoint slides (and then some!) and you – the viewer – could decide seamlessly and instantly whether you wanted to dive into the background or just enjoy the great music (or maybe do both at the same time). That's something you can't do on a standard DVD, and it's also something that doesn't require a gigantic TV, elaborate surround-sound system, or expensive disc player to appreciate. 
&lt;/p&gt;&lt;p&gt;Whenever people write off interactivity as a gimmick or something nobody needs, I think fondly back to the day when a University friend first showed me the World Wide Web. I just shrugged... why would anyone need that? I could get exactly the same information through &lt;a href="http://en.wikipedia.org/wiki/Gopher_%28protocol%29"&gt;Gopher&lt;/a&gt;, only faster! 
&lt;/p&gt;&lt;p&gt;How things change.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7309651" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ptorr/archive/tags/Randomness/default.aspx">Randomness</category><category domain="http://blogs.msdn.com/ptorr/archive/tags/HD+DVD/default.aspx">HD DVD</category></item><item><title>Good News </title><link>http://blogs.msdn.com/ptorr/archive/2008/01/14/good-news.aspx</link><pubDate>Mon, 14 Jan 2008 23:02:10 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7111121</guid><dc:creator>ptorr</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/ptorr/comments/7111121.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ptorr/commentrss.aspx?PostID=7111121</wfw:commentRss><wfw:comment>http://blogs.msdn.com/ptorr/rsscomments.aspx?PostID=7111121</wfw:comment><description>&lt;p&gt;Not one but &lt;em&gt;two&lt;/em&gt; bits of good news this morning!
&lt;/p&gt;&lt;p&gt;Firstly, TWICE &lt;a href="http://www.twice.com/article/CA6522356.html"&gt;reported on Toshiba's plans for HD DVD&lt;/a&gt; this year. Probably the biggest news was that the entry-level HD-A3 player will have a new recommended price of only $149 and that the higher-end models will get similar price cuts. 
&lt;/p&gt;&lt;p&gt;And in other news: &lt;a href="http://www.thetripledoor.net/event.aspx?eid=2899"&gt;Howard Jones is coming to Seattle&lt;/a&gt;! &lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7111121" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ptorr/archive/tags/Randomness/default.aspx">Randomness</category><category domain="http://blogs.msdn.com/ptorr/archive/tags/HD+DVD/default.aspx">HD DVD</category></item><item><title>What I’ve Learnt about Coffee Lids</title><link>http://blogs.msdn.com/ptorr/archive/2007/12/16/what-i-ve-learnt-about-coffee-lids.aspx</link><pubDate>Mon, 17 Dec 2007 08:04:50 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:6786388</guid><dc:creator>ptorr</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/ptorr/comments/6786388.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ptorr/commentrss.aspx?PostID=6786388</wfw:commentRss><wfw:comment>http://blogs.msdn.com/ptorr/rsscomments.aspx?PostID=6786388</wfw:comment><description>&lt;p&gt;When I first moved to the US over eight years ago, I thought it was very odd that people put lids on their take-away coffee. I found it quite strange to drink through a hole in a lid rather than to just drink directly from the cup, and routinely discarded the lids in order to enjoy my beverage the old-fashioned way. I thought it odder still that people would walk and drink their coffee &lt;em&gt;at the same time&lt;/em&gt;, but it didn't take long for me to realise that this was a supremely useful activity afforded by the afore-mentioned lids.
&lt;/p&gt;&lt;p&gt;The annoying thing was that although the lids generally did a good job of keeping coffee in its place, every so often a small amount of coffee would escape from the cup and drip onto my clothes. And with &lt;a href="http://en.wikipedia.org/wiki/Murphy%27s_law"&gt;Murphy's Law&lt;/a&gt; in full effect, it typically happened when I had on a clean white shirt. Before a meeting. 
&lt;/p&gt;&lt;p&gt;Initially I thought it was just random manufacturing defects in the lids, or that the lids weren't on well enough. But one day I investigated further into the drippage and uncovered the culprit: the seam in the cup where the cardboard is joined together. If the lid is placed in such a way that the mouthpiece is more-or-less directly over the cup's seam, chances are that the seal will not be completely air-tight, and when you tilt the cup to take a drink the coffee will drip out of the cup and onto your freshly-laundered shirt. The solution? Simply rotating the lid to ensure the mouthpiece is directly opposite the seam appears to solve the problem – at least it has never happened to me since I started being more vigilant about lid placement.
&lt;/p&gt;&lt;p&gt;I've never really thought this was much of a revelation – it seems like common sense, really – but having explained it to two friends recently I decided maybe it's not that obvious after all, and hence this completely non-HD-DVD-related blog post :-)&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=6786388" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ptorr/archive/tags/Randomness/default.aspx">Randomness</category><category domain="http://blogs.msdn.com/ptorr/archive/tags/Coffee/default.aspx">Coffee</category></item><item><title>HD DVD Emulator for Xbox 360!</title><link>http://blogs.msdn.com/ptorr/archive/2007/12/13/hd-dvd-emulator-for-xbox-360.aspx</link><pubDate>Fri, 14 Dec 2007 04:22:15 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:6766599</guid><dc:creator>ptorr</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/ptorr/comments/6766599.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ptorr/commentrss.aspx?PostID=6766599</wfw:commentRss><wfw:comment>http://blogs.msdn.com/ptorr/rsscomments.aspx?PostID=6766599</wfw:comment><description>&lt;p&gt;It's finally here! &lt;a href="http://www.thisishddvd.com/emulator/details.aspx"&gt;The Xbox 360 HD DVD Emulator&lt;/a&gt; went live today, enabling content authors to test their HD DVD content in a real-world consumer player before committing it to a shiny disc. This can save a &lt;strong&gt;lot&lt;/strong&gt; of time and a &lt;strong&gt;lot&lt;/strong&gt; of money for those folks building advanced HD DVD titles. It might help you save your hair, too :-)
&lt;/p&gt;&lt;p&gt;"But," you might be saying, "doesn't Microsoft already ship an &lt;a href="http://blogs.msdn.com/amyd/archive/2007/04/11/getting-started-with-hd-dvd.aspx"&gt;HD DVD Simulator&lt;/a&gt; for free? Why would I want this emulator?"
&lt;/p&gt;&lt;p&gt;Good question. Here are just a few reasons why:
&lt;/p&gt;&lt;ol&gt;&lt;li&gt;The simulator only plays Windows Media files, and poorly at that. The emulator plays real multiplexed EVOB files (with VC-1 and AVC and TrueHD etc.) that you will ship on the real disc.
&lt;/li&gt;&lt;li&gt;The simulator doesn't support subtitles or multiple audio tracks. The emulator does, enabling you to actually test them.
&lt;/li&gt;&lt;li&gt;The simulator shows you how your code performs on your desktop PC. The emulator shows you how it performs on real shipping hardware.
&lt;/li&gt;&lt;li&gt;The simulator has some primitive logging functionality, but you need to &lt;a href="http://blogs.msdn.com/ptorr/archive/2007/06/27/helpful-tracing-routines.aspx"&gt;do some work yourself&lt;/a&gt;. The emulator has very robust logging for all aspects of HDi playback (including markup timing!).
&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;There are obviously more reasons to use the emulator, but that's a quick rundown of some of the key reasons why you might want to do it. Of course the simulator is still great for doing early title development – where access to real video and multiple audio tracks might not matter – because using the PC enables a great edit-run-debug workflow. But the emulator is absolutely critical for putting everything together, fine-tuning your code, verifying performance and compatibility, and running a through a thorough test pass prior to check-disc replication.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=6766599" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ptorr/archive/tags/HD+DVD/default.aspx">HD DVD</category><category domain="http://blogs.msdn.com/ptorr/archive/tags/iHD/default.aspx">iHD</category><category domain="http://blogs.msdn.com/ptorr/archive/tags/HDi/default.aspx">HDi</category></item><item><title>“Open Season” Hits #2; World Scratches Head</title><link>http://blogs.msdn.com/ptorr/archive/2007/12/04/open-season-hits-2-world-scratches-head.aspx</link><pubDate>Wed, 05 Dec 2007 05:56:28 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:6661267</guid><dc:creator>ptorr</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/ptorr/comments/6661267.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ptorr/commentrss.aspx?PostID=6661267</wfw:commentRss><wfw:comment>http://blogs.msdn.com/ptorr/rsscomments.aspx?PostID=6661267</wfw:comment><description>&lt;p&gt;If you follow the High-Definition format war at all, you're probably familiar with the weekly sales breakdown published in &lt;em&gt;Home Media Magazine&lt;/em&gt; and other places. If you &lt;a href="http://www.nxtbook.com/nxtbooks/questex/hom120207/index.php?startpage=18"&gt;checked them last week&lt;/a&gt;, you would have seen something strange. 
&lt;/p&gt;&lt;p&gt;Something very strange.
&lt;/p&gt;&lt;p&gt;At #1, you have &lt;em&gt;Live Free or Die Hard&lt;/em&gt; on Blu-ray. This makes sense, since it is both a new release and the action genre fits the "PlayStation 3" demographic of many Blu-ray disc buyers, but then at #2 we see the animated comedy &lt;em&gt;Open Season&lt;/em&gt;. Now if you took a double-take on reading that one, you're not alone. &lt;em&gt;Open Season&lt;/em&gt; doesn't appear anywhere on last week's &lt;a href="http://www.nxtbook.com/nxtbooks/questex/hom120207/index.php?startpage=32"&gt;standard DVD sales or rentals charts&lt;/a&gt;, nor does it appear on the &lt;a href="http://www.nxtbook.com/nxtbooks/questex/hom120207/index.php?startpage=20"&gt;electronic sell-through and download charts&lt;/a&gt;. In fact, &lt;em&gt;Open Season&lt;/em&gt; hasn't appeared on any of the &lt;a href="http://www.videoscan.com/about.html"&gt;Nielsen VideoScan&lt;/a&gt; charts for months – if ever. A quick jump over to Amazon shows why it isn't on any of the regular charts – it was released on &lt;a href="http://www.amazon.com/Open-Season-Blu-ray-Martin-Lawrence/dp/B000L22SGG/"&gt;January 30 2007&lt;/a&gt;, and with an &lt;a href="http://www.boxofficemojo.com/movies/?id=openseason06.htm"&gt;estimated US box office&lt;/a&gt; of only $84m it is highly unlikely anyone would be rushing to buy the title almost a year after it was released. So what gives?
&lt;/p&gt;&lt;p&gt;Well, look no further than &lt;a href="http://www.1pstart.com/best-buy-to-offer-40gb-ps3-nba-08-and-open-season-blu-ray-for-399/"&gt;this Best Buy advertisement&lt;/a&gt;, which bundled &lt;em&gt;Open Season&lt;/em&gt; with the 40Gb PlayStation 3 for Thanksgiving. Everyone who bought a PlayStation 3 at Best Buy got a free copy of the movie, and those give-aways also got counted as "sales" towards the numbers reported each week in &lt;em&gt;Home Media Magazine&lt;/em&gt;. This is a smart move for the BDA, which gets to give away a movie the customer wasn't going to buy anyway (hence no lost sales), &lt;em&gt;plus&lt;/em&gt; they get to inflate the number of discs "sold" and put out a splashy "&lt;a href="http://www.nxtbook.com/nxtbooks/questex/hom120207/index.php?startpage=36"&gt;7 out of 10 discs were Blu-ray&lt;/a&gt;" ad. 
&lt;/p&gt;&lt;p&gt;This is one clear anomaly in the VideoScan data, but if you consider how many bundles, freebies, give-aways, BOGOs (Buy-One-Get-One Free), etc. have been offered by the Blu-ray Disc studios, you can start to draw your own conclusions.
&lt;/p&gt;&lt;p&gt;Oh, and before you ask "What about the &lt;a href="http://www.thelookandsoundofperfect.com/_pdf/perfect_hd_dvd_offer_redemption_form.pdf"&gt;5 free movies&lt;sup&gt;[PDF]&lt;/sup&gt;&lt;/a&gt; the HD DVD Promotion Group is offering?" the answer is easy – those don't count in the weekly sales data because they are mail-in rebates; only things physically scanned at the checkout get counted (irrespective of whether they are free or not). This means that,  for example, the copy of &lt;a href="http://www.amazon.com/dp/B000JHO4L0/"&gt;&lt;em&gt;King Kong&lt;/em&gt; bundled with the Xbox HD DVD add-on&lt;/a&gt; also doesn't get counted, nor does the copy of &lt;a href="http://www.amazon.com/dp/B000XGJH1O/"&gt;&lt;em&gt;Spider-Man 3&lt;/em&gt; bundled with the PlayStation 3&lt;/a&gt;. Only barcodes of discs scanned at registers get counted, even if the customer doesn't have to pay for them.
&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=6661267" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ptorr/archive/tags/HD+DVD/default.aspx">HD DVD</category></item><item><title>Maintaining Callback Semantics</title><link>http://blogs.msdn.com/ptorr/archive/2007/10/24/maintaining-callback-semantics.aspx</link><pubDate>Wed, 24 Oct 2007 21:29:55 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5655276</guid><dc:creator>ptorr</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/ptorr/comments/5655276.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ptorr/commentrss.aspx?PostID=5655276</wfw:commentRss><wfw:comment>http://blogs.msdn.com/ptorr/rsscomments.aspx?PostID=5655276</wfw:comment><description>&lt;p&gt;One of the key programming concepts in HDi is the use of asynchronous processing with callback functions. The HDi platform exposed to title authors is not multi-threaded (which helps reduce the complexity of writing applications), but many of the functions of the player are asynchronous in nature. For example, all the I/O in HDi (both local and network) is asynchronous so that the on-screen experience isn't degraded while the script waits for a long I/O call to complete. Instead, the script asks the player for a resource and then just keeps on plugging away. At some future point in time the resource will become available, the player will notify the script via a callback function, and the script can act on the resource without any further waiting.
&lt;/p&gt;&lt;p&gt;As is common in any programming environment, many developers have built "helper functions" around some of the built-in HDi functions in order to centralise error handling, simplify high-level tasks, or for other various reasons. This is all well and good, but I have seen some developers use a programming pattern for these helpers that will lead to bugs down the road. I'm going to show an example of this bad pattern (and how to avoid it), but first here's an example of many people's first attempt at asynchronous programming:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// Global variables to hold state&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;var&lt;/span&gt; done = &lt;span style="color:blue"&gt;false&lt;/span&gt;;&lt;br/&gt;&lt;span style="color:blue"&gt;var&lt;/span&gt; result = 0;
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// Copy a file and return when it is done&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; CopyFileHelper(src, dest)&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:green"&gt;// Copy the file, providing a simple callback function&lt;br/&gt;&lt;/span&gt;  FileIO.copy(src, dest, &lt;span style="color:blue"&gt;true&lt;/span&gt;, IOFinishedHandler);
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  &lt;span style="color:green"&gt;// Wait until the callback is called&lt;br/&gt;&lt;/span&gt;  &lt;span style="color:blue"&gt;while&lt;/span&gt; (!done)&lt;br/&gt;    ; &lt;span style="color:green"&gt;// nothing
&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  &lt;span style="color:blue"&gt;return&lt;/span&gt; result;&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// Function to handle the callback and stop the loop&lt;br/&gt;// inside CopyFileHelper&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; IOFinishedHandler(errorInfo)&lt;br/&gt;{&lt;br/&gt;  result = errorInfo;&lt;br/&gt;  done = &lt;span style="color:blue"&gt;true&lt;/span&gt;;&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;
 &lt;/p&gt;&lt;p&gt;This code will never work, so luckily nobody has ever shipped a title like this (that I know of!). Nevertheless, it is interesting to learn &lt;em&gt;why&lt;/em&gt; it doesn't work. The basic idea is to have a sentinel value (in this case, &lt;strong&gt;done&lt;/strong&gt;) that is initially &lt;strong&gt;false&lt;/strong&gt;. The &lt;strong&gt;FileIO&lt;/strong&gt; operation is called and is provided a callback handler that will (i) stash the result of the I/O function for later use; and (ii) set the sentinel to &lt;strong&gt;true&lt;/strong&gt;. The main function then performs a &lt;a href="http://en.wikipedia.org/wiki/Busy_wait"&gt;busy wait&lt;/a&gt; until the &lt;strong&gt;done&lt;/strong&gt; variable is set to &lt;strong&gt;true&lt;/strong&gt; by the callback, at which point the &lt;strong&gt;while&lt;/strong&gt; loop ends and the function returns.
&lt;/p&gt;&lt;p&gt;Although this kind of programming might work on a natively multi-threaded platform like .NET or Java, it won't work in HD DVD because of the way application time is scheduled. (Note it would also still be a bad idea on .NET or Java, but that's another story). In HD DVD, application code (including markup timing and script execution) is executed in a tick-based fashion. At the start of a tick, the necessary script code &lt;em&gt;for that tick&lt;/em&gt; is executed (including event handlers, timers, and other callbacks) and then execution is passed to the markup layer. The markup layer performs timing and layout operations, and then the script is given another chance to run if it needs to handle any markup events. Finally, the markup page is generated and the system starts over again on a new tick. This all happens on a single thread. At the same time, other operations like A/V decoding and the &lt;strong&gt;FileIO&lt;/strong&gt; APIs are happening on different threads.
&lt;/p&gt;&lt;p&gt;What happens in this case is that the &lt;strong&gt;FileIO.copy&lt;/strong&gt; function is called, a new thread is created to handle the copy operation, and then the script goes into the busy-wait loop. At some point in the future, the copy operation will finish and player will schedule the callback to happen &lt;em&gt;on the next tick&lt;/em&gt;. But because the script code is busy waiting for &lt;strong&gt;done&lt;/strong&gt; to become &lt;strong&gt;true&lt;/strong&gt;, &lt;em&gt;the current tick never ends&lt;/em&gt; and so your player's menu appears to hang. This is why nobody actually ships this code :-)
&lt;/p&gt;&lt;p&gt;OK, so that's the impossibly-bad way of doing async IO. Here's the promised programming pattern that you should look out for and fix:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// Copy a file and do some common logging, etc&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; CopyFileHelper(src, dest, clientCallbackHandler)&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:green"&gt;// Perform some common, useful stuff...&lt;br/&gt;&lt;/span&gt;  &lt;span style="color:green"&gt;// ...&lt;br/&gt;&lt;/span&gt;  &lt;span style="color:green"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  &lt;span style="color:green"&gt;// Copy the file, providing the caller's callback handler&lt;br/&gt;&lt;/span&gt;  &lt;span style="color:green"&gt;// so they can continue when it is done&lt;br/&gt;&lt;/span&gt;  &lt;span style="color:blue"&gt;try&lt;br/&gt;&lt;/span&gt;  {&lt;br/&gt;    FileIO.copy(src, dest, &lt;span style="color:blue"&gt;true&lt;/span&gt;, clientCallbackHandler);&lt;br/&gt;  }&lt;br/&gt;  &lt;span style="color:blue"&gt;catch&lt;/span&gt; (ex)&lt;br/&gt;  {&lt;br/&gt;    &lt;span style="color:green"&gt;// Oops! Got an exception, so log it, convert to a FAILED result,&lt;br/&gt;&lt;/span&gt;    &lt;span style="color:green"&gt;// and let the caller know via their callback&lt;br/&gt;&lt;/span&gt;    &lt;br/&gt;    LogError(&lt;span style="color:#a31515"&gt;"Exception while copying "&lt;/span&gt; + src + &lt;span style="color:#a31515"&gt;" to "&lt;/span&gt; + dest, ex);&lt;br/&gt;    clientCallbackHandler(FileIO.FAILED);&lt;br/&gt;  }&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;
 &lt;/p&gt;&lt;p&gt;In this case, at least we're not trying to break the laws of physics. In most cases, this code will work fine. If the &lt;strong&gt;copy&lt;/strong&gt; operation doesn't throw an exception, the client's callback is called and everyone is happy. If the &lt;strong&gt;copy&lt;/strong&gt; operation &lt;em&gt;does&lt;/em&gt; throw, we log the error and convert it into a failed result for their callback. This makes programming much easier for the client since they don't have to worry about exceptions anymore; they just treat all failures the same way... right?
&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Wrong.
&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Although it looks like you've made life simpler, you've just introduced a subtle bug that may not bite you until sometime in the future. The problem is that you've broken the semantics of the client's callback, which is that &lt;em&gt;callbacks are always called asynchronously&lt;/em&gt;.&lt;strong&gt;
			&lt;em&gt;You should never call a callback synchronously because the client code may not be expecting it&lt;/em&gt;. 
&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Imagine the client has code like this:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// Perform a sequence of operations involving a file copy&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; ClientCode()&lt;br/&gt;{&lt;br/&gt;  DoFirstThing();
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  CopyFileHelper(src, dest, DoThirdThing);
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  DoSecondThing();&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; DoFirstThing() { &lt;span style="color:green"&gt;/* ... */&lt;/span&gt; }&lt;br/&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; DoSecondThing() { &lt;span style="color:green"&gt;/* ... */&lt;/span&gt; }&lt;br/&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; DoThirdThing(result) { &lt;span style="color:green"&gt;/* ... */&lt;/span&gt; }
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;
 &lt;/p&gt;&lt;p&gt;Under normal circumstances (no exceptions), the order of function calls will be &lt;strong&gt;DoFirstThing&lt;/strong&gt;, &lt;strong&gt;DoSecondThing&lt;/strong&gt;, and then at some future tick, &lt;strong&gt;DoThirdThing.&lt;/strong&gt; Even if there is an error while copying, the code will progress in this sequence and the client can happily deal with any copy failures in &lt;strong&gt;DoThirdThing&lt;/strong&gt;, secure in the knowledge that &lt;strong&gt;DoSecondThing&lt;/strong&gt; has already completed. But what happens when there is an exception (which may not have happened during testing)? Now the order of execution is &lt;strong&gt;DoFirstThing&lt;/strong&gt;, &lt;strong&gt;DoThirdThing&lt;/strong&gt;, &lt;strong&gt;DoSecondThing&lt;/strong&gt;, all in the same tick. &lt;em&gt;You have reversed the order of the last two steps!&lt;/em&gt;
	&lt;/p&gt;&lt;p&gt;If &lt;strong&gt;DoSecondThing&lt;/strong&gt; performs a critical task that is needed before &lt;strong&gt;DoThirdThing&lt;/strong&gt; can succeed, the code is now broken and won't operate properly even though &lt;strong&gt;DoThirdThing&lt;/strong&gt; may be coded robustly to deal with the &lt;strong&gt;copy&lt;/strong&gt; error. The solution is to simply schedule the client's callback to happen at a later time, thus preserving the execution order of the client's code. This is easily done with a single-frame, non-repeating timer. Here's an example of how you might do it:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  &lt;span style="color:green"&gt;// ... same code as before ...&lt;br/&gt;&lt;/span&gt;  &lt;span style="color:blue"&gt;catch&lt;/span&gt; (ex)&lt;br/&gt;  {&lt;br/&gt;    &lt;span style="color:green"&gt;// Oops! Got an exception, so log it, convert to a FAILED result,&lt;br/&gt;&lt;/span&gt;    &lt;span style="color:green"&gt;// and let the caller know via their callback&lt;br/&gt;&lt;/span&gt;    &lt;br/&gt;    LogError(&lt;span style="color:#a31515"&gt;"Exception while copying "&lt;/span&gt; + src + &lt;span style="color:#a31515"&gt;" to "&lt;/span&gt; + dest, ex);&lt;br/&gt;    ScheduleCallback(ExceptionCallback);&lt;br/&gt;  }
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  &lt;span style="color:green"&gt;// Closure used to pass arguments to the callback &lt;br/&gt;&lt;/span&gt;  &lt;span style="color:blue"&gt;function&lt;/span&gt; ExceptionCallback()&lt;br/&gt;  {&lt;br/&gt;    &lt;span style="color:blue"&gt;try&lt;br/&gt;&lt;/span&gt;    {&lt;br/&gt;      clientCallbackHandler(FileIO.FAILED);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;catch&lt;/span&gt; (ex)&lt;br/&gt;    {&lt;br/&gt;      &lt;span style="color:green"&gt;// Client callback failed; nowhere to go from here&lt;br/&gt;&lt;/span&gt;      LogError(&lt;span style="color:#a31515"&gt;"Fatal exception while calling client callback"&lt;/span&gt;, ex);&lt;br/&gt;    }&lt;br/&gt;  }&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// Call the function on the next tick. If you need to pass arguments to&lt;br/&gt;// the function, then pass a closure (nested function) to do the work&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; ScheduleCallback(callback)&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:blue"&gt;var&lt;/span&gt; t = createTimer(&lt;span style="color:#a31515"&gt;"00:00:00:01"&lt;/span&gt;, 1, callback);&lt;br/&gt;  t.autoReset = &lt;span style="color:blue"&gt;false&lt;/span&gt;;&lt;br/&gt;  t.enabled = &lt;span style="color:blue"&gt;true&lt;/span&gt;;&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;
 &lt;/p&gt;&lt;p&gt;In this new code, if an exception occurs then rather than calling the callback directly, we schedule it to be called on the next tick via a couple of helper functions. We need the &lt;strong&gt;ExceptionCallback&lt;/strong&gt; helper function in order to pass arguments to the callback (timers never pass arguments themselves), and we use the &lt;strong&gt;ScheduleCallback&lt;/strong&gt; helper to &lt;a href="http://blogs.msdn.com/ptorr/archive/2007/08/29/using-timers-effectively-in-hdi.aspx"&gt;avoid closures&lt;/a&gt;. This ensures that the client's code always executes in the order expected, and thus reduces your chances of having weird bugs in the future.
&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5655276" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ptorr/archive/tags/Script/default.aspx">Script</category><category domain="http://blogs.msdn.com/ptorr/archive/tags/HDi/default.aspx">HDi</category></item><item><title>Sliced bread ain’t got nuthin’ on this!</title><link>http://blogs.msdn.com/ptorr/archive/2007/10/02/sliced-bread-ain-t-got-nuthin-on-this.aspx</link><pubDate>Tue, 02 Oct 2007 21:49:21 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5246358</guid><dc:creator>ptorr</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/ptorr/comments/5246358.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ptorr/commentrss.aspx?PostID=5246358</wfw:commentRss><wfw:comment>http://blogs.msdn.com/ptorr/rsscomments.aspx?PostID=5246358</wfw:comment><description>&lt;p&gt;Forget being the best thing &lt;em&gt;since&lt;/em&gt; sliced bread – this is the best thing &lt;em&gt;ever&lt;/em&gt;. Well maybe not &lt;em&gt;quite &lt;/em&gt;that good, but it's still darn cool!
&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:14pt"&gt;Finally – &lt;span style="color:red"&gt;&lt;strong&gt;FINALLY!&lt;/strong&gt;&lt;/span&gt; – you can get &lt;a href="http://blogs.msdn.com/webdevtools/archive/2007/03/02/jscript-intellisense-in-orcas.aspx"&gt;decent IntelliSense for JScript inside Visual Studio&lt;/a&gt;! 
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Holy hotcakes, Batman! This is so awesome you have to &lt;a href="http://msdn2.microsoft.com/en-us/vstudio/aa700831.aspx"&gt;download Visual Studio 2008 Beta 2&lt;/a&gt;
		&lt;strong&gt;right now&lt;/strong&gt; and try it out. 
&lt;/p&gt;&lt;p&gt;Back when I was on the script team, we couldn't get any features into Visual Studio (much to the chagrin of our customers) because all the hype was around ASP.NET. The rich client was dead. It was all about the server. Nobody needed client-side script any more. Everything was a web form post-back.
&lt;/p&gt;&lt;p&gt;But now that AJAX and Silverlight and all these other buzzwords are suddenly important, people taking notice of the little script language that could. 
&lt;/p&gt;&lt;p&gt;Congrats and thanks to the Visual Web Developer and JScript teams – at last, JScript is getting some of the respect it has always deserved! :-)&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5246358" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ptorr/archive/tags/Visual+Studio/default.aspx">Visual Studio</category><category domain="http://blogs.msdn.com/ptorr/archive/tags/Script/default.aspx">Script</category><category domain="http://blogs.msdn.com/ptorr/archive/tags/HDi/default.aspx">HDi</category></item><item><title>Wikipedia editing</title><link>http://blogs.msdn.com/ptorr/archive/2007/09/30/wikipedia-editing.aspx</link><pubDate>Sun, 30 Sep 2007 21:43:59 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5213056</guid><dc:creator>ptorr</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/ptorr/comments/5213056.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ptorr/commentrss.aspx?PostID=5213056</wfw:commentRss><wfw:comment>http://blogs.msdn.com/ptorr/rsscomments.aspx?PostID=5213056</wfw:comment><description>&lt;p&gt;Short post: In the interests of full disclosure, I've started editing &lt;a href="http://wikipedia.org/"&gt;Wikipedia&lt;/a&gt; on various topics related to HD DVD. Initially I made several "anonymous" edits, but decided to &lt;a href="http://en.wikipedia.org/wiki/User:Petertorr"&gt;create an account&lt;/a&gt; for transparency and so I can "watch" pages as they change. 
&lt;/p&gt;&lt;p&gt;Basically I am just posting this here so nobody "discovers" my edits in the future and claims this is some "hidden agenda" by Microsoft to "lend credibility" by faking "grass roots" spin. Whatever.
&lt;/p&gt;&lt;p&gt;Anyway, I'll still be doing the majority of my posting ("Haha," some of you might say, "not so much lately!") on this blog. The Wikipedia editing is mostly about keeping the pages interesting, up-to-date, and &lt;em&gt;accurate&lt;/em&gt;. &lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5213056" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ptorr/archive/tags/Randomness/default.aspx">Randomness</category><category domain="http://blogs.msdn.com/ptorr/archive/tags/HD+DVD/default.aspx">HD DVD</category></item><item><title>Why Old Films Still Benefit from High-Def</title><link>http://blogs.msdn.com/ptorr/archive/2007/09/26/why-old-films-still-benefit-from-high-def.aspx</link><pubDate>Thu, 27 Sep 2007 00:32:56 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5152940</guid><dc:creator>ptorr</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/ptorr/comments/5152940.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ptorr/commentrss.aspx?PostID=5152940</wfw:commentRss><wfw:comment>http://blogs.msdn.com/ptorr/rsscomments.aspx?PostID=5152940</wfw:comment><description>&lt;p&gt;Every now and then, I hear people make comments like "Movies more than 5 years old won't look any better in HD because they were shot before HD was invented – the movie studios are lying to you about better quality!" 
&lt;/p&gt;&lt;p&gt;This is horribly, &lt;em&gt;horribly&lt;/em&gt;, &lt;strong&gt;&lt;em&gt;horribly&lt;/em&gt;&lt;/strong&gt; wrong, and I'm not quite sure where this idea stems from.
&lt;/p&gt;&lt;p&gt;A "Full HD" image (as the marketing people like to call it) is &lt;a href="http://en.wikipedia.org/wiki/Full_hd"&gt;1920 pixels wide by 1080 pixels high&lt;/a&gt;. Now that sounds like an awful lot of pixels (especially compared to Standard Definition) but it's small compared to the "resolution" of a good film stock. 
&lt;/p&gt;&lt;p&gt;Although film doesn't have well-defined "pixels" like digital video does – it is based on tiny particles inside the film's chemical structure – you can get an approximation to digital pixels and the current thinking is that it is around 6- to 8- thousand pixels &lt;em&gt;horizontally &lt;/em&gt;(not vertically) – something the marketing folks would probably call "Ultimate HD 4320p" or some other silly name.
&lt;/p&gt;&lt;p&gt;This brings up an interesting difference in how resolution is counted – in the consumer world, resolution is counted vertically – 480, 720, and 1080 all refer to the number of &lt;em&gt;rows&lt;/em&gt; of pixels. But in the &lt;a href="http://en.wikipedia.org/wiki/Digital_cinema"&gt;digital cinema&lt;/a&gt; world, it is counted horizontally – 2K and 4K refer to the number of &lt;em&gt;columns&lt;/em&gt; of pixels. So your "1080p" TV is pretty close to a "2K" system in the digital cinema world (although not quite).
&lt;/p&gt;&lt;p&gt;What this means is that pretty much any movie or TV show shot on a 35mm (or larger) film stock has far more resolution than even "Full HD" can show, and so old movies still get a big improvement by going to HD DVD (or Blu-ray) versus standard DVD. It all depends on the quality of the master and the time and effort taken in transferring it from film to digital and then compressing it for release.
&lt;/p&gt;&lt;p&gt;You want proof? Look at the review of &lt;a href="http://hddvd.highdefdigest.com/casablanca.html"&gt;&lt;em&gt;Casablanca&lt;/em&gt;&lt;/a&gt; (1942) for an example of how old films can look simply stunning in high definition. 
&lt;/p&gt;&lt;p&gt;&lt;strong&gt;[Update]
&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Another thing to consider is that despite the fact that film has more resolution than "Full HD," there are lots of problems with the way film is typically viewed that can dampen the experience. Prints get scratched. Projectors get out of focus. Screens get dirty. Theatres dim the light bulbs to save money. All of these things can lead to a poor-quality film presentation, so with a good HD transfer and a well-calibrated display you might even see &lt;em&gt;more&lt;/em&gt; on an HD DVD disc than you would in the average supermall Cineplex.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5152940" width="1" height="1"&gt;</description></item><item><title>Using Timers Effectively in HDi</title><link>http://blogs.msdn.com/ptorr/archive/2007/08/29/using-timers-effectively-in-hdi.aspx</link><pubDate>Thu, 30 Aug 2007 05:21:47 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:4638148</guid><dc:creator>ptorr</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/ptorr/comments/4638148.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ptorr/commentrss.aspx?PostID=4638148</wfw:commentRss><wfw:comment>http://blogs.msdn.com/ptorr/rsscomments.aspx?PostID=4638148</wfw:comment><description>&lt;p&gt;The use of timers in HDi applications is very common, and there are a few things you should keep in mind when using them to avoid performance issues when playing back your title. 
&lt;/p&gt;&lt;p&gt;I will categorise these as:
&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The autoReset problem
&lt;/li&gt;&lt;li&gt;The closure problem
&lt;/li&gt;&lt;li&gt;The re-use problem
&lt;/li&gt;&lt;li&gt;The general-abuse problem
&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;
 &lt;/p&gt;&lt;h2&gt;The AutoReset Problem
&lt;/h2&gt;&lt;p&gt;This problem stems from the fact that, by default, timers created in HDi are &lt;em&gt;repeating timers&lt;/em&gt;, meaning that they will fire over and over and over again until you tell them to stop. Sometimes this is what the content author wants, but more often than not what they really need is a single notification after the timeout period has elapsed (what we call a "one-shot" timer). It's essentially the difference between &lt;a href="http://msdn2.microsoft.com/en-us/library/ms536753.aspx"&gt;setTimeout&lt;/a&gt; and &lt;a href="http://msdn2.microsoft.com/en-us/library/ms536749.aspx"&gt;setInterval&lt;/a&gt; in the browser DOM.
&lt;/p&gt;&lt;p&gt;If you want a one-shot timer, the following pattern should be avoided:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// Create a timer; note it auto-repeats by default&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;var&lt;/span&gt; t = createTimer(TIME, CLOCK, callback);&lt;br/&gt;t.enabled = &lt;span style="color:blue"&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; callback()&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:green"&gt;// do stuff...
&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  &lt;span style="color:green"&gt;// Now disable the timer; sometimes people forget this step!&lt;br/&gt;&lt;/span&gt;  t.enabled = &lt;span style="color:blue"&gt;false&lt;/span&gt;;&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Instead, consider the more straightforward (and less bug-prone) version:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// Create a timer and make sure it only fires once&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;var&lt;/span&gt; t = createTimer(TIME, CLOCK, callback);&lt;br/&gt;t.autoReset = &lt;span style="color:blue"&gt;false&lt;/span&gt;;&lt;br/&gt;t.enabled = &lt;span style="color:blue"&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; callback()&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:green"&gt;// do stuff...&lt;br/&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Sometimes, the problem is compounded because the author &lt;em&gt;assumes&lt;/em&gt; the timer is a one-shot timer, and that in order to get repeating semantics they need to re-create the timer every time. That results in code like this:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// Create a timer; note it auto-repeats by default&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;var&lt;/span&gt; t = createTimer(TIME, CLOCK, callback);&lt;br/&gt;t.enabled = &lt;span style="color:blue"&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; callback()&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:green"&gt;// do stuff...
&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  &lt;span style="color:green"&gt;// Now re-create the timer to ensure we get called again&lt;br/&gt;&lt;/span&gt;  t = createTimer(TIME, CLOCK, callback);&lt;br/&gt;  t.enabled = &lt;span style="color:blue"&gt;true&lt;/span&gt;;&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Now what happens is that every time the timer fires, a new timer is created to fire on the same schedule! So after the first callback, there are two timers. After the second callback, there are four timers. After the third callback, there are eight timers, and so on. Eventually the old timers will get garbage collected by the script engine (and stop firing), but this could take a long time to happen depending on what else your script is doing. This is clearly a waste of resources and should be avoided; if you need a repeating timer, leave &lt;strong&gt;autoReset&lt;/strong&gt; at its default value and don't re-create the timer later on (although I prefer explicitly setting &lt;strong&gt;autoReset&lt;/strong&gt; to &lt;strong&gt;true&lt;/strong&gt; to convey the intent that it really should repeat). Otherwise, set &lt;strong&gt;autoReset&lt;/strong&gt; to &lt;strong&gt;false&lt;/strong&gt; at the time you create the timer, and you will be happy. 
&lt;/p&gt;&lt;h2&gt;The Closure Problem
&lt;/h2&gt;&lt;p&gt;In ECMAScript, a "closure" is a geeky name for a nested function. The reason we call them closures is to do with the way they affect the lifetime of other objects. I don't want to go into great detail now, but essentially a nested function maintains a reference to all the local variables of its containing function, thereby "closing them off" from being released by the garbage collector. Normally this isn't a problem for ECMAScript, because sooner or later the closure will die and thus the other objects it has been keeping references to will also die. 
&lt;/p&gt;&lt;p&gt;For example:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; MakeAClosure()&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:green"&gt;// Gobble up some memory&lt;br/&gt;&lt;/span&gt;  &lt;span style="color:blue"&gt;var&lt;/span&gt; bigObj = CreateECMAScriptObjectThatUsesLotsOfMemory();
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  &lt;span style="color:green"&gt;// Deliberately set up a circular reference&lt;br/&gt;&lt;/span&gt;  bigObj.circularReference = Closure;
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  &lt;span style="color:green"&gt;// Return the closure&lt;br/&gt;&lt;/span&gt;  &lt;span style="color:blue"&gt;return&lt;/span&gt; Closure;
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  &lt;span style="color:green"&gt;// Define the nested function (closure)&lt;br/&gt;&lt;/span&gt;  &lt;span style="color:blue"&gt;function&lt;/span&gt; Closure()&lt;br/&gt;  {&lt;br/&gt;    &lt;span style="color:green"&gt;// doesn't really matter what Closure does;&lt;br/&gt;&lt;/span&gt;    &lt;span style="color:green"&gt;// it still keeps a referenceto bigObj&lt;br/&gt;&lt;/span&gt;  }&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; foo()&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:green"&gt;// Get the closure&lt;br/&gt;&lt;/span&gt;  &lt;span style="color:blue"&gt;var&lt;/span&gt; closure = MakeAClosure();&lt;br/&gt;  &lt;span style="color:green"&gt;// maybe use it, maybe not...&lt;br/&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// Call foo&lt;br/&gt;&lt;/span&gt;foo();
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;In this example, we have an outer function (&lt;strong&gt;MakeAClosure&lt;/strong&gt;), a nested function (&lt;strong&gt;Closure&lt;/strong&gt;), another global function (&lt;strong&gt;foo&lt;/strong&gt;), and some global code that calls &lt;strong&gt;foo&lt;/strong&gt;. Here's what happens during execution:
&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;foo&lt;/strong&gt; gets called
&lt;/li&gt;&lt;li&gt;&lt;strong&gt;foo&lt;/strong&gt; calls &lt;strong&gt;MakeAClosure&lt;/strong&gt;
		&lt;/li&gt;&lt;li&gt;&lt;div&gt;&lt;strong&gt;MakeAClosure&lt;/strong&gt; creates a large object that uses up some memory, and stashes it in &lt;strong&gt;bigObj&lt;/strong&gt;
			&lt;/div&gt;&lt;ul&gt;&lt;li&gt;The nested function&lt;strong&gt; Closure&lt;/strong&gt; gets a reference to &lt;strong&gt;bigObj&lt;/strong&gt; for reasons that I won't get in to here (check sections 10.2.3, 13, and 13.2 of ECMA-262 for technical details... or I can post more later :-)) 
&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;MakeAClosure&lt;/strong&gt; explicitly makes &lt;strong&gt;bigObj&lt;/strong&gt; hold a reference to &lt;strong&gt;Closure&lt;/strong&gt; so they both refer to each other – a classic &lt;a href="http://en.wikipedia.org/wiki/Reference_counting"&gt;circular reference problem&lt;/a&gt;
		&lt;/li&gt;&lt;li&gt;&lt;div&gt;&lt;strong&gt;MakeAClosure&lt;/strong&gt; returns the &lt;strong&gt;Closure&lt;/strong&gt;
				&lt;strong&gt;Function&lt;/strong&gt; object back to &lt;strong&gt;Foo&lt;/strong&gt;
			&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Note that this includes the reference to &lt;strong&gt;bigObj&lt;/strong&gt;
				&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;foo&lt;/strong&gt; stores the &lt;strong&gt;Function&lt;/strong&gt; object inside the &lt;strong&gt;closure&lt;/strong&gt; variable 
&lt;/li&gt;&lt;li&gt;&lt;strong&gt;foo&lt;/strong&gt; exits
&lt;/li&gt;&lt;li&gt;Sooner or later, the garbage collector runs and sees that &lt;strong&gt;bigObj&lt;/strong&gt; is used by &lt;strong&gt;closure&lt;/strong&gt;, and &lt;strong&gt;closure&lt;/strong&gt; is used by &lt;strong&gt;bigObj&lt;/strong&gt;, but there is no way to access either of them (they are not "reachable") so it can safely kill both of them
&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Here everything is fine and dandy. But if &lt;strong&gt;bigObj&lt;/strong&gt; where a &lt;em&gt;non&lt;/em&gt;-ECMAScript object (eg, a Host object), the memory would never be reclaimed in Step 8 because the garbage collector cannot prove that &lt;strong&gt;bigObj&lt;/strong&gt; is unreachable – maybe some other part of the system still relies on it – and so it has to assume that &lt;strong&gt;closure&lt;/strong&gt; is still reachable, too. And since &lt;strong&gt;closure&lt;/strong&gt; holds on to &lt;strong&gt;bigObj&lt;/strong&gt;, the native object is never going to release itself, and the memory is leaked. 
&lt;/p&gt;&lt;p&gt;Perhaps it's clearer with an example.... using Timers, of course :-)
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// Perform two animations, one after the other&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; DoTwoPartAnimation()&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:green"&gt;// Perform some animation over 1 second&lt;br/&gt;&lt;/span&gt;  document.foo.animateProperty(&lt;span style="color:#a31515"&gt;"y"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;"0px;100px"&lt;/span&gt;, 1);
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  &lt;span style="color:green"&gt;// Setup a callback to do the other animation after the first is done&lt;br/&gt;&lt;/span&gt;  &lt;span style="color:blue"&gt;var&lt;/span&gt; t = createTimer(&lt;span style="color:#a31515"&gt;"00:00:01:00"&lt;/span&gt;, 1, DoPartTwo);&lt;br/&gt;  t.autoReset = &lt;span style="color:blue"&gt;false&lt;/span&gt;;&lt;br/&gt;  t.enabled = &lt;span style="color:blue"&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  &lt;span style="color:blue"&gt;function&lt;/span&gt; DoPartTwo()&lt;br/&gt;  {&lt;br/&gt;    &lt;span style="color:green"&gt;// Perform second part of animation&lt;br/&gt;&lt;/span&gt;    document.bar.animateProperty(&lt;span style="color:#a31515"&gt;"x"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;"0px;100px"&lt;/span&gt;, 1);&lt;br/&gt;  }&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;This simple example illustrates a common pattern in HDi – chaining together two or more script-based animations by having a timer fire after the first animation is complete (this is unnecessary with markup animations, but they're not always practical). 
&lt;/p&gt;&lt;p&gt;In this case, &lt;strong&gt;DoTwoPartAnimation&lt;/strong&gt; creates a local &lt;strong&gt;Timer&lt;/strong&gt; variable, &lt;strong&gt;t&lt;/strong&gt;, and gives it a reference to the nested function &lt;strong&gt;DoPartTwo&lt;/strong&gt; as the callback function. As we learnt above, &lt;strong&gt;DoPartTwo&lt;/strong&gt; maintains a reference to all of &lt;strong&gt;DoTwoPartAnimation&lt;/strong&gt;'s variables, including the timer &lt;strong&gt;t&lt;/strong&gt;. So even after the timer has fired, and &lt;strong&gt;DoPartTwo&lt;/strong&gt; has executed, we will leak the timer object (and the &lt;strong&gt;Function&lt;/strong&gt; object for &lt;strong&gt;DoPartTwo&lt;/strong&gt;) because the circular reference can't be broken.
&lt;/p&gt;&lt;p&gt;The good news is that there are at least three ways to solve this problem:
&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Avoid closures altogether
&lt;/li&gt;&lt;li&gt;Explicitly break the cycle
&lt;/li&gt;&lt;li&gt;Avoid making the timer a local variable
&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;The first is the simplest, and in the case above we can solve the problem by simply making &lt;strong&gt;DoPartTwo&lt;/strong&gt; another global function instead of a nested function. Then although the timer &lt;strong&gt;t&lt;/strong&gt; has a reference to &lt;strong&gt;DoPartTwo&lt;/strong&gt;, &lt;strong&gt;DoPartTwo&lt;/strong&gt; does not have a reference back to &lt;strong&gt;t&lt;/strong&gt; and so the timer will be garbage collected sooner or later (which in turn will release &lt;strong&gt;DoPartTwo&lt;/strong&gt;). The problem here is that often you &lt;em&gt;need&lt;/em&gt; to use a nested function in order to correctly perform the callback operation – for example, the callback needs to know some of the parameters that were originally passed to the containing function in order to complete its task. 
&lt;/p&gt;&lt;p&gt;In that case, another simple solution is to explicitly break the cycle by manually releasing the reference to the timer. For example, we could change the &lt;strong&gt;DoPartTwo&lt;/strong&gt; function slightly to look like this:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  &lt;span style="color:blue"&gt;function&lt;/span&gt; DoPartTwo()&lt;br/&gt;  {&lt;br/&gt;    document.bar.animateProperty(&lt;span style="color:#a31515"&gt;"x"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;"0px;100px"&lt;/span&gt;, 1);
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;    &lt;span style="color:green"&gt;// Explicitly break the circular reference&lt;br/&gt;&lt;/span&gt;    t = &lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;  }
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Now, as with the 1&lt;sup&gt;st&lt;/sup&gt; work-around, the script engine can eventually garbage collect &lt;strong&gt;t&lt;/strong&gt;, which in turn will release &lt;strong&gt;DoPartTwo&lt;/strong&gt;. Nevertheless, the problem with this solution – as with all solutions that require that the programmer religiously follow some strict rules all the time – is that you might forget to add this line to your callback, or you might have a &lt;strong&gt;return&lt;/strong&gt; statement near the top of the function, or you might throw an exception, or... there are various ways your program might miss this opportunity to break the cycle.
&lt;/p&gt;&lt;p&gt; So that leaves us with... my preferred approach, which is simply to make your own helper function – much like the web's &lt;strong&gt;setTimeout&lt;/strong&gt; – that will create the timer for you. Here's a simple example:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// Call callback after timecode has elapsed&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; SetTimeout(timecode, callback)&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:blue"&gt;var&lt;/span&gt; t = createTimer(timecode, 1, callback);&lt;br/&gt;  t.autoReset = &lt;span style="color:blue"&gt;false&lt;/span&gt;;&lt;br/&gt;  t.enabled = &lt;span style="color:blue"&gt;true&lt;/span&gt;;&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Now you can simply replace all the pesky &lt;strong&gt;createTimer&lt;/strong&gt; / &lt;strong&gt;autoReset&lt;/strong&gt; / &lt;strong&gt;enabled&lt;/strong&gt; code with a single call to &lt;strong&gt;SetTimeout&lt;/strong&gt;, and avoid all the closure issues, too! 
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// Perform two animations, one after the other&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; DoTwoPartAnimation()&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:green"&gt;// Perform some animation over 1 second&lt;br/&gt;&lt;/span&gt;  document.foo.animateProperty(&lt;span style="color:#a31515"&gt;"y"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;"0px;100px"&lt;/span&gt;, 1);
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  &lt;span style="color:green"&gt;// Setup a callback to do the other animation after 1s&lt;br/&gt;&lt;/span&gt;  SetTimeout(&lt;span style="color:#a31515"&gt;"00:00:01:00"&lt;/span&gt;, DoPartTwo);
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;  &lt;span style="color:blue"&gt;function&lt;/span&gt; DoPartTwo()&lt;br/&gt;  {&lt;br/&gt;    &lt;span style="color:green"&gt;// Perform second part of animation&lt;br/&gt;&lt;/span&gt;    document.bar.animateProperty(&lt;span style="color:#a31515"&gt;"x"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;"0px;100px"&lt;/span&gt;, 1);&lt;br/&gt;  }&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;The closure issues are avoided because &lt;strong&gt;DoPartTwo&lt;/strong&gt; has zero knowledge of the Timer object &lt;strong&gt;t&lt;/strong&gt;, which is a local variable of the &lt;strong&gt;SetTimeout&lt;/strong&gt; function. Although the timer has a reference to &lt;strong&gt;DoPartTwo&lt;/strong&gt;, the opposite is not true and so there is no circular reference.
&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Note about HTTPClient
&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Note that this "closure problem" also exists with &lt;strong&gt;HTTPClient&lt;/strong&gt; objects and the &lt;strong&gt;onStateChange&lt;/strong&gt; function. The same solutions exist for breaking the circular reference though – avoid closures, null out the object once it is finished (eg, &lt;strong&gt;STATE_COMPLETED&lt;/strong&gt;, &lt;strong&gt;STATE_ERROR&lt;/strong&gt;, or &lt;strong&gt;STATE_ABORT&lt;/strong&gt;), or use a helper to create the object.
&lt;/p&gt;&lt;p&gt;In general it doesn't affect other callback-based APIs like &lt;strong&gt;FileIO.openTextStream&lt;/strong&gt; or &lt;strong&gt;XMLParser.parse&lt;/strong&gt; because these are global objects, not local instances created by the enclosing function. The API will release the callback function as soon as it has been used (so it won't leak), and it doesn't really matter how many references there are to global objects; they will always exist.
&lt;/p&gt;&lt;h2&gt;The Re-Use Problem
&lt;/h2&gt;&lt;p&gt;Timer re-use is something that can be done correctly, but is often done incorrectly. Sometimes this is done by mistake (eg, forgetting to put &lt;strong&gt;var&lt;/strong&gt; in front of a variable declaration, making it global), but other times it is deliberately done and leads to brittle code. 
&lt;/p&gt;&lt;p&gt;Here's a canonical example:
&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:green"&gt;// Create timer; assume it is enabled&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;var&lt;/span&gt; timer = createTimer(TIME, CLOCK, CALLBACK);
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; EventHandler()&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:green"&gt;// Clobber global timer; assume it is enabled&lt;br/&gt;&lt;/span&gt;  timer = createTimer(TIME2, CLOCK2, CALLBACK2);&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left: 36pt"&gt;&lt;span style="font-family:Courier New; font-size:10pt"&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt; CancelTheTimer()&lt;br/&gt;{&lt;br/&gt;  &lt;span style="color:green"&gt;// Which timer are you cancelling?&lt;br/&gt;&lt;/span&gt;  timer.enabled = &lt;span style="color:blue"&gt;false&lt;/span&gt;;&lt;br/&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;The code is pretty much self explanatory:
&lt;/p&gt;&lt;ol&gt;&lt;li&gt;A global &lt;strong&gt;timer&lt;/strong&gt; is created
&lt;/li&gt;&lt;li&gt;An event handler clobbers the first &lt;strong&gt;timer&lt;/strong&gt; and creates a new one
&lt;/li&gt;&lt;li&gt;A cancel function disables the &lt;strong&gt;timer&lt;/strong&gt;
		&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;The problem is that depending on the order in which &lt;strong&gt;EventHandler&lt;/strong&gt; and &lt;strong&gt;CancelTheTimer&lt;/strong&gt; are called, different things may happen. If &lt;strong&gt;CancelTheTimer&lt;/strong&gt; is called before &lt;strong&gt;EventHandler&lt;/strong&gt;, it will cancel the global timer, but if the order is reversed then the global timer will fire and the event-handler timer will be disabled instead! 
&lt;/p&gt;&lt;p&gt;Even if you &lt;em&gt;think&lt;/em&gt; you know the order in which events will occur, they may not always fire in exactly the same order – especially if they rely on user input or some asynchronous processes such as the progression of the title timeline. Better to always assume that the worst will happen, and program accordingly.
&lt;/p&gt;&lt;p&gt;The simple solution here is to always use a unique name for your timers, or ensure they are local variables that won't conflict with other timers. (I would say to use the &lt;strong&gt;SetTimeout&lt;/strong&gt; function from above, but that won't allow you to cancel the timer). 
&lt;/p&gt;&lt;h2&gt;The General-Abuse Problem
&lt;/h2&gt;&lt;p&gt;The "general abuse" category basically covers any use of a timer that is unnecessary given the feature set of HDi. Sometimes authors abuse timers because they are not aware of HDi's built-in features (in which case it is generally easy to change from an abusive timer to use the right feature), or sometimes it is because the application's design has been built around timers rather than some more elegant solution (in which case it can be much harder to re-work the code to use fewer timers).
&lt;/p&gt;&lt;p&gt;Two prime examples of the former include:
&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Performing many &lt;strong&gt;set&lt;/strong&gt; operations on a repeating 1-frame timer, rather than using the &lt;strong&gt;&amp;lt;animate&amp;gt;&lt;/strong&gt; element in markup or the &lt;strong&gt;animateProperty&lt;/strong&gt; API
&lt;/li&gt;&lt;li&gt;Constantly polling &lt;strong&gt;currentTitle.elapsedTime&lt;/strong&gt; to check for a specific timecode, rather than using an &lt;strong&gt;&amp;lt;event&amp;gt;&lt;/strong&gt; in markup or a &lt;strong&gt;PauseAt&lt;/strong&gt; in the playlist
&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Examples of the latter are harder to come by, but (with no intention of bashing the other format) we have seen authors trying to replicate the behaviour of BD-J applications on HD DVD by an over-zealous use of timers, since they don't necessarily realise that the HDi system will do a lot of the heavy lifting for them.
&lt;/p&gt;&lt;h2&gt;Final Thought
&lt;/h2&gt;&lt;p&gt;An astute observer might ask the question "what happens if a timer is garbage-collected &lt;em&gt;before&lt;/em&gt; it fires?" Good question. It is entirely possible that the local variable &lt;strong&gt;t&lt;/strong&gt; used in these examples will be collected before the timer fires, especially if the timeout is quite long (say, several minutes). The answer is that the HD DVD specification requires timers to fire &lt;em&gt;at least once&lt;/em&gt;, even if the script engine has released all references to them.
&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=4638148" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ptorr/archive/tags/Script/default.aspx">Script</category><category domain="http://blogs.msdn.com/ptorr/archive/tags/HDi/default.aspx">HDi</category></item><item><title>Simple ACA dumper</title><link>http://blogs.msdn.com/ptorr/archive/2007/07/05/simple-aca-dumper.aspx</link><pubDate>Fri, 06 Jul 2007 00:36:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:3713342</guid><dc:creator>ptorr</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/ptorr/comments/3713342.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ptorr/commentrss.aspx?PostID=3713342</wfw:commentRss><wfw:comment>http://blogs.msdn.com/ptorr/rsscomments.aspx?PostID=3713342</wfw:comment><description>&lt;P&gt;Quick one today – if you have an ACA with some files in it, you can use the &lt;STRONG&gt;createaca&lt;/STRONG&gt; tool (provided as part of the &lt;A href="http://blogs.msdn.com/amyd/archive/2007/04/11/getting-started-with-hd-dvd.aspx" mce_href="http://blogs.msdn.com/amyd/archive/2007/04/11/getting-started-with-hd-dvd.aspx"&gt;Jumpstart Kit&lt;/A&gt;) to list the files inside it. Trouble is that the output is not very helpful; it contains too much information. &lt;/P&gt;
&lt;P&gt;So here is a simple JScript file you can run on the output of &lt;STRONG&gt;createaca -r&lt;/STRONG&gt; to just dump the filenames (and it checks for duplicates, too!). Just copy to &lt;STRONG&gt;dumpaca.js&lt;/STRONG&gt; (or the file of your choice) and run it from a command prompt. It expects a file named &lt;STRONG&gt;filelist.txt&lt;/STRONG&gt; to exist in the same folder. Modifications to do whatever you want to do should be trivial... &lt;/P&gt;
&lt;P style="MARGIN-LEFT: 36pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"&gt;&lt;SPAN style="COLOR: green"&gt;// Open file named "filelist.txt"&lt;BR&gt;‎&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; fso = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; ActiveXObject(&lt;SPAN style="COLOR: #a31515"&gt;"Scripting.FileSystemObject"&lt;/SPAN&gt;);&lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; stream = fso.OpenTextFile(&lt;SPAN style="COLOR: #a31515"&gt;"filelist.txt"&lt;/SPAN&gt;);&lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; contents = stream.ReadAll(); &lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN-LEFT: 36pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"&gt;&lt;SPAN style="COLOR: green"&gt;// Regular expression to search for DATA_FNAME followed by a name&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; re =/DATA_FNAME : ((?:\w|\.)+)/g; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN-LEFT: 36pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"&gt;&lt;SPAN style="COLOR: green"&gt;// Lists of result data&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; names = {};&lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; nameList = [];&lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; result;&lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; dupes = []; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN-LEFT: 36pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"&gt;&lt;SPAN style="COLOR: green"&gt;// Search for every instance of the regular expression&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;while&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt; != (result = re.exec(contents)))&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; name = result[1]; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN-LEFT: 36pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"&gt;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: green"&gt;// Record dupes&lt;BR&gt;&lt;/SPAN&gt;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: blue"&gt;if&lt;/SPAN&gt; (names[name] != &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;)&lt;BR&gt;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dupes.push(name);&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: green"&gt;// else record new values&lt;BR&gt;&lt;/SPAN&gt;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: blue"&gt;else&lt;BR&gt;&lt;/SPAN&gt;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;names[name] = nameList.length;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;nameList.push(name);&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;} &lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN-LEFT: 36pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"&gt;&lt;SPAN style="COLOR: green"&gt;// Print results&lt;BR&gt;&lt;/SPAN&gt;print(&lt;SPAN style="COLOR: #a31515"&gt;"---------- Complete file list ----------"&lt;/SPAN&gt;); &lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN-LEFT: 36pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"&gt;&lt;SPAN style="COLOR: blue"&gt;for&lt;/SPAN&gt; (&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; i &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt; nameList)&lt;BR&gt;&amp;nbsp;&amp;nbsp;print(nameList[i]); &lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN-LEFT: 36pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"&gt;&lt;SPAN style="COLOR: green"&gt;// Print dupes&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;if&lt;/SPAN&gt; (dupes.length &amp;gt; 0)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;print(&lt;SPAN style="COLOR: #a31515"&gt;"---------- Duplicate file names ----------"&lt;/SPAN&gt;); &lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN-LEFT: 36pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"&gt;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: blue"&gt;for&lt;/SPAN&gt; (&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; j &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt; dupes)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(dupes[j]);&lt;BR&gt;} &lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN-LEFT: 36pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"&gt;&lt;SPAN style="COLOR: green"&gt;// Helper&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;function&lt;/SPAN&gt; print(s) { WScript.Echo(String(s)); }&lt;BR&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=3713342" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ptorr/archive/tags/Script/default.aspx">Script</category><category domain="http://blogs.msdn.com/ptorr/archive/tags/iHD/default.aspx">iHD</category><category domain="http://blogs.msdn.com/ptorr/archive/tags/HDi/default.aspx">HDi</category></item></channel></rss>