Wednesday, April 15, 2009

Flash, translate transform, and x/y co-ordinates

"Self Documenting Code" is my mantra - code that is intuitive.

Flash is not.

I lost yet another hour or two trying to get a simple translate transform working. The doco fails to mention that :

If you set x or y for a DisplayObject, it effectively overwrites any translate transform in the current transformation matrix for the DisplayObject.

I hate to be harsh, but you could at least mention this in the documentation! XAML transformations apply in addition to any x/y co-ordinates set on an object. Not so in Flash.

And so if you apply a transformation, and then set a DisplayObject's x/y properties, you might be puzzled wondering why the translation component of the transformation is not taking effect.

That's why.

It makes sense enough when you understand it, but it proves once again that Adobe is often worse than useless at writing documentation and at designing intuitive APIs. Why did I have to spend an hour or two figuring this out for myself? It should have been documented, or been more apparent in the API itself.

Thursday, April 9, 2009

Flash automatically merges shapes at compile time

Here be dragons.

Flash automatically combines shapes at compile time.

So if you were expecting to place two or more shapes on the stage and be able to access them via the stage's getChildAt method, you're in for an interesting time.

It's not as simple as "Flash combines all shapes into a single shape". It seems to work based on z-index.

Suppose you add two shapes to the stage, then add a textbox, then add a third shape.

You'll discover at runtime that the first two shapes have been merged into one, but the third has not.

If you play with the z-index ("send to back", "send to front") in the Flash IDE, you'll discover that the ONLY thing that controls whether or not two particular shapes get merged at compile time is whether or not they are neighbours in the z-index.

(Technically, they need to be part of the same unbroken sequence of shapes in the z-index, so for example if you add three shapes to the stage in succession, they will be combined into a single shape at compilation time, because they will appear one after the other in the z-index.)

Unfortunately, I failed to find any documentation which mentions this, or any other Flash developers having their plans thwarted by this 'feature'. So I hereby post my "here be dragons" flag.

The solution? If you NEED the shapes to be drawn in Flash (as opposed to drawn in ActionScript at runtime) and you NEED them to be separate shapes at runtime, then cut them out of your document and paste them into a temporary document, then paste one shape back, then create an off-stage dynamic text field (to form a z-index divider), then paste in the next shape, and so on, and so forth.

Of course, it should be very rare that you need to do this kind of thing, but I came across such an instance today, and lost several hours due to this seemingly undocumented 'feature'.

Tuesday, April 7, 2009

Accessing your Ubuntu partition from Windows

Virtual Volumes is beta software, but for read-only access to an Ubuntu partition, its everything I need.

I have a relatively recent installation of Ubuntu, and it is brilliant. Its native support of NTFS means I can access all my Windows files from Ubuntu. But going the other way is trickier. Virtual Volumes fills this gap (for my simple requirements).

Virtual Volumes is a desktop app, not a kernel driver. For my purposes, that was a benefit, because it meant I didn't need to reboot after installation, and there is nothing consuming extra system resources when I'm not accessing my Linux partition.

The same guy who created Virtual Volumes also created a very popular tool called explore2fs, but for no apparent reason, it failed to work with my recent Ubuntu installation.

I also tried DiskInternals' Linux-reader which again, is popular and probably works for many Linux distributions, but failed to work with my recent Ubuntu installation.

In short, Virtual Volumes is well worth a try, either as your first choice, or as a backup option if other options fail.

(Thanks to UbuntuGeek.com for pointing me to the DiskInternals Linux-Reader tool.)

P.S. If you want a kernel-mode driver, fs-driver.org looks promising, but I can't vouch for it.

P.P.S. Huge kudos to chrysocome.net! Virtual Volumes is my friend. :o)

aspnet_compiler and its mysterious silent failures

Around the year 2000, Microsoft started actually doing some things extremely well.

Internet Explorer 4 was the most abysmal web browser ever to disgrace the human race, but Internet Explorer 5 was remarkably solid.

Windows ME was their buggiest and single worst desktop operating system ever, but Windows 2000 was impressive.

Visual Basic 6, ASP, VBA, COM and all that stuff was a bit same-old, same-old - a clunky development experience. But the .NET framework truly ushered in a new era of programming productivity.

The .NET framework itself is awesome. Microsoft has never produced anything better, in my opinion, than the .NET framework.

But within the .NET framework lives an incredibly buggy tool called aspnet_compiler.

Unfortunately, some of us are forced to rely upon it.

It frequently fails with no error message.

Nada on the console.

Nada in the event log.

Just absolute silence.

It pretends it has happily successfully finished, but in actual fact, something has gone wrong and it absolutely refuses to tell you about it.

And that wastes hours. And hours. And did I mention, hours.

Today I lost about an hour and a half. Aspnet_compiler would succeed if I excluded any one of my dozen or so subfolders in my web root folder. But if I tried to include all my subfolders, it would grind away as if it was working successfully, and then it would suddenly fail without any error message.

I got it to the point that I could compile successfully if I excluded any one of several files in one particular folder, but if I tried to include them all, it would fail with no error message.

But if I removed a different subfolder from the root folder, I could include all those files that previously I could include all-but-one of.

It was aspnet_compiler demonstrating its classic fickleness. I think Microsoft invented it for no other purpose than to waste developers' time. OK, maybe that's getting a little too harsh...

Anyhow, lo-and-behold, when I copied the entire problematic precompilation-input folder to another location and tried again, it failed, but this time with a compilation error message that at least I can do something about.

What was the problem?

It seems that aspnet_compiler is unable to cope with long file paths. It seems that once the absolute file path to any file in the precompilation input exceeds some threshhold, aspnet_compiler becomes very fragile, and sometimes succeeds, but with slightly different input, sometimes fails.

By copying my source code to a temporary folder near the root of my drive, I shortened the maximum file path, and thus avoided aspnet_compiler's file-path-length issues.

But that's not the only stupid thing aspnet_compiler is known to do.

For example, sure, at least I'm getting a compilation error now. But the compilation error I'm getting actually has nothing to do with any of the files which, if I exclude, it all compiles successfully. i.e. the thing its tripping over now is not a real issue. But at least it gives me something to focus more specifically on.

Such are the vagueries of life with aspnet_compiler.

But wait, there's more!

Suppose you have two ASPX files in the same namespace and with the same base class name, and suppose it works fine during testing in IIS before precompilation. All good and well, you'd think. And then you try to precompile. And aspnet_compiler dies saying nothing more than that it "failed with error code 1" (or is it 0? it's a while since I last had this problem, though I've had it too many times before). The cause? aspnet_compiler requires that all class names throughout the entire web app be unique within their respective namespaces. Fair enough. It's a reasonably intuitive rule now that you mention it. But I had to figure it out for myself. 'Coz aspnet_compiler doesn't tell you what's wrong in this instance - it just dies with that very obscure error message.

And so I regret that I ever bought Microsoft's hype that aspnet_compiler is now the best and recommended pathway to shipping websites. The tool is unstable, unreliable, and frequently complains about non-existent problems.

But aside from aspnet_compiler, I love the .NET framework. It's the best thing Microsoft has ever done.

Monday, April 6, 2009

Mail server setup, mailing lists, and Microsoft's "Smart Network Data Services"

I received a weird email today, and it first it looked like spam. It claimed to be from staff@hotmail.com, and I don't interact with Hotmail.com.

But on closer examination of the message, I realised there was something here worth investigating further.

Dear Jonathan Field,

Smart Network Data Services has determined that the trusted email address for your network 203.89.209.146 through 203.89.209.150 has either changed or the email address previously trusted is no longer valid. Consequently, your access to data for this network has been disabled, pending re-authorization.

Please visit the Smart Network Data Services site to remove the network and re-add the network with a valid trusted email address.

You are receiving this because you have signed up to be part of a preview release of Smart Network Data Services, or a Smart Network Data Services user has requested that this email be sent to this address. Smart Network Data Services is a revolutionary Windows Live Mail initiative, designed to allow everyone who owns IP space to contribute to the fight against spam and protect e-mail as a valued communications, productivity and commerce tool. If you have questions about our privacy policy, please read our privacy statement available at http://privacy.live.com.

I don't have a clue what "Smart Network Data Services" is, and I'm pretty sure I never signed up for a preview of it, but I Google it and it's actually quite interesting.

Smart Network Data Services home page.

Yeah - their website is hard to navigate, and poorly written, but there's some very useful data inside.

If you run a mail server and/or have clients with mailing lists, Smart Network Data Services promises to be of some assistance in the process of identifying how Hotmail treats messages from your mail servers.

I only just came across it now, and I found it extremely hard to navigate, so don't ask me for help using it, but I did manage to sign up and access an "IP address status" page - which thankfully told me I'm not a spammer. :o)

Its sad but true that managing a legitimate mailing list or mail server in the 21st century requires highly developed technical skills, and constant monitoring of the ever-changing anti-spam landscape. Within that context, Microsoft's Smart Network Data Services is a new tool to help keep the emails flowing.

Flash vs SilverLight : SilverLight will win (my prediction)

I've been living in Adobe Flash / ActionScript land for the last few weeks, and there has been a very unexpected side-effect.

Today, when I was working in Microsoft Visual Studio again, it was a joy to use!

I always used to think Microsoft Visual Studio was HIDEOUSLY slow and inefficient - and it is - but after inflicting Adobe Flash on myself for a week and a half, Visual Studio seems absolutely awesome.

As yet another example of the sheer stupidity which pervades Adobe Flash and its implementation of ActionScript :

1) Grab a big Adobe Flash project - you know, one that takes ten seconds to build.
2) Open it in Flash CS4.
3) Press Ctrl+Enter to run it in test mode.
4) Close the runner.
5) Press Ctrl+Enter to run it again, as if you just wanted to check out one more thing.

Guess what?

Adobe Flash is so stupid, that it doesn't notice that nothing has changed since the last build, and so it rebuilds the project, wasting more time.

And it doesn't seem to have any incremental build either. If you have a large project, and change one tiny thing ANYWHERE in the project, you face the entire laborious build process once again.

On a fast (3ghz QuadCore) computer, I am finding Flash makes debugging a major chore by making tedious to iteratively change and test.

Visual Studio in contrast? Do a debug run, and it will build and run. Run again without changing anything? It knows it doesn't need to rebuild, so it starts instantly. Change anything? It supports incremental build to a certain extent.

It makes Adobe Flash look like it comes from the 90s, or earlier. Except, that it's actually Adobe Flash CS4 - the very latest and greatest in 2009. Ouch - that sucks.

Oh - and I thought Visual Studio was bad, because the incremental build is actually quite limited. Turns out, Flash seems to have no incremental build at all.

And don't talk about load times - I thought Visual Studio load times were bad. But after Flash, it feels zippy.

And today, Flash crashed on me literally, hmmm, about ten times. I mean, crashed, dead, have to restart the app, and sorry about any unsaved work. That kind of crash.

Visual Studio is INCREDIBLY inefficient, but at least it hardly ever crashes. And Flash's inefficiencies make Visual Studio look like a racecar.

Add to this the documentation errors and erroneous compiler errors that define Flash 10 with ActionScript 3, and you have the perfect recipe for the most imperfect program I ever imagined could wear the Adobe name.

If it were a house, the "for sale" sign out front would say "full of potential".

Translation : it needs a LOT of work.

My bet?

Adobe will drop the ball (or continue to drop the ball).

SilverLight will win.

And it will take roughly 8 to 10 years to happen.

Sunday, April 5, 2009

Graphical add/commit in Bazaar without the slowness of TortoiseBZR

How can you quickly & easily pick which files you want to add to Bazaar?

I've had too many painful experiences (not Bazaar's fault) of going "bzr add", and then discovering that amidst the dozens of files I DID want to add, there were a whole bunch that I DIDN'T.

Removing them is a bit of a pain - I tend to use very long self-descriptive folder names and file names, so if a big "bzr add" operation added dozens of files, and I needed to manually remove perhaps a dozen or more, it was very time inefficient.

Fortunately, Bazaar has the answer! I just didn't discover it until yesterday.

bzr qadd

That little "q" at the beginning of the "add" command brings up a GUI window, allowing you to very quickly & easily select exactly which files you want added.

Bazaar, I love you! :o)



P.S. You can also use "bzr qcommit", which is a FABULOUS way to do a partial commit. And "bzr qdiff" if you want a diff that is easier to read than "bzr diff".

UPDATE : The preceding works fine if you used the Windows installer for Bazaar. If you are using Linux, you need to install a Bazaar plugin called QBzr - see bialix's comments on this article.

Flash SimpleButton, and MOUSE_OVER and MOUSE_OUT not firing

Adobe Flash documentation is often worse than useless. Useless would be "tells us nothing we didn't already know". WORSE than useless is "tells us information that is NOT correct, causing us to waste time".

Their flash.display.SimpleButton is the culprit once again.

I was dynamically generating SimpleButton instances in ActionScript 3, and adding MOUSE_OVER and MOUSE_OUT event handlers.

But the event handlers were never firing.

I reviewed the documentation - the SimpleButton definitely supports the MOUSE_OVER and MOUSE_OUT events.

I tried adding the event handlers to the flash.text.TextField instances which formed the button states, but that didn't work either - the events simply never ever fired.

I finally figured out what's going wrong. It's that SimpleButton constructor once again.

Here's what the doco says (false info - worse than useless) about the SimpleButton constructor :

Any or all of the display objects that represent the various button states can be set as parameters in the constructor.

ANY OR ALL ... CAN BE. In other words, it is OPTIONAL to set the various states using the constructor.

In a previous blog post, I noted that, despite the CLAIM that the constructor arguments are optional, the first argument is actually MANDATORY.

If you don't specify the first argument, the button never transitions between states, even if you set the states later using the upState, overState etc properties.

But if you DO specify the first argument, the up-and-over animation works correctly.

That was from that previous blog post.

Well, the new lesson for today's blog post is that in fact ALL FOUR arguments to the constructor are MANDATORY if you wish to get MOUSE_OVER and MOUSE_OUT events from the SimpleButton.

It doesn't make sense, and it makes mockery of their (poor as too often the case) documentation, and in fact makes mockery of Adobe's ability to design an intuitive API, but it is the case.

The one saving grace is that we can specify the SAME DisplayObject for all four constructor arguments. e.g.

var sb:SimpleButton = new SimpleButton(MySprite, MySprite, MySprite, MySprite);

(And of course, the other way you can do it is subclass SimpleButton and set the upState, overState etc properties in your own constructor. Basically, by the end of the constructor, those values must be set.)



As a final note, I was just about to paste the simple test code I whipped up, to make it extremely easy for you to reproduce my test results, but as I did so, Adobe Flash suddenly died on me and completely disappeared from the taskbar without even its usual "Adobe Flash just died" popup message.

All I can say is that I am disgusted with Adobe Flash - not only is the documentation often worse than useless, but the program itself is fragile, and crashes on me usually more than once per work day.

And this is Flash CS4 - their latest and greatest...

Friday, April 3, 2009

Merging unrelated branches in Bazaar

The skinny : 'cd <working-tree-to-merge-into>', then 'bzr merge <branch-to-merge-with> -r0..-1', and then 'bzr commit "Merged with {bla}"'.

I continue to love Bazaar.

I've wondered for a while : "How can I merge two completely unrelated branches?"

Scenario : I'm working on a large website with an extensive ASP.NET section, and an extensive Flash section. The ASP.NET section is very mature. The Flash section has just begun. I want to be able to version control the Flash stuff in the same repository as the ASP.NET stuff, but in unrelated branches, and eventually merge the branches once the Flash stuff matures somewhat.

Can do! But it took a bit of figuring out.

Along the way, I kept bumping my head against this error message from Bazaar :

bzr: ERROR: Branches have no common ancestor, and no merge base revision was specified.

Suppose my folders were :

C:\BzrRepo\AspDotNetStuff

and

C:\BzrRepo\FlashStuff

I was trying to do :

C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff

That wasn't working, so I tried using the --revision= option to specify a base revision (as hinted by the error message) :

C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff --revision=1

Still no go.

So I looked at the --change= option.

C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff --change=1..27

(27 being the latest revision number in the FlashStuff branch.)

Still no go - it tells me that the --change= option cannot handle revision ranges - it can only handle one specific revision number.

OK, so what if I try to integrate just the very latest change?

C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff --change=27

That didn't work either. Instead, it created lots of conflicts.

Ah - finally I think I see the light!

C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff --change=1

Yes! Progress! It worked! i.e. I have to start with the very first change in the unrelated branch.

Now will it let me merge the remaining changes?

C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff

Nope - it complains that I have uncommitted changes.

Easily fixed :

C:\BzrRepo\AspDotNetStuff> bzr commit -m "Merged with FlashStuff revision 1"

Good.

And now let's try the merge again :

C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff

Bonanza! It worked!

And I have now successfully merged two COMPLETELY UNRELATED branches that lived under the same repository.

In summary, the quick way to do it :

C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff --change=1
C:\BzrRepo\AspDotNetStuff> bzr commit -m "Merged with FlashStuff revision 1"
C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff
C:\BzrRepo\AspDotNetStuff> bzr commit -m "Merged fully with FlashStuff"

And I'm a happy camper. :o)



UPDATE : Thanks to bialix (in the comments) for pointing out a simpler way to accomplish the same thing :

C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff -r0..-1
C:\BzrRepo\AspDotNetStuff> bzr commit -m "Merged with FlashStuff"

Slightly different syntax, accomplishes the same thing, but more concise. Did I mention I love Bazaar?

Thursday, April 2, 2009

Flash bugs: dynamic TextField and letterSpacing issue

I'm creating TextField instances in ActionScript, modeled after one TextField instance in the Flash UI designer.

There are two stupid problems.

Problem 1:

The first is that Flash is very forgetful.

Suppose I go :

tb.text = 'Some new text';

Just like that, key TextField settings are lost! Idiotic. Things like letterSpacing get reset to zero.

The solution (noted by others) is to :

var tf:flash.text.TextFormat = tb.getTextFormat();
tb.text = 'Some new text';
tb.setTextFormat(tf);

If that makes sense to anyone, I suppose there probably are airborne sows.

But it kinda does the trick. Kinda.

Enter: problem the second

If I'm doing all this with an embedded font, the aforesaid hack DOES NOT WORK.

At least, not without a bit more effort.

I had the original textbox, built in to the Flash stage. Let's call it tbOriginal.

Then I have my dynamic textboxes, modelled off the original.

tbCreatedAtRuntime.text = 'Some text here';
tbCreatedAtRuntime.setTextFormat(tbOriginal.getTextFormat());

Nice - does the trick, except that the letterSpacing is shot.

So I play with the letter spacing. I try all sorts of values.

tbCreatedAtRuntime.text = 'Some text here';
var tf:flash.text.TextFormat = tbOriginal.getTextFormat();
tf.letterSpacing = 0.55; /* I tried lots of different values here. */
tbCreatedAtRuntime.setTextFormat(tf);

The problem was that, regardless of what letterSpacing value I set, it would often make no difference whatsoever to the overall length of the string.

But it was weirder than that. Once I got down to about 0.54, the string length jumped down very significantly. It was like the letterSpacing had a very course rounding applied, such that there was only one "real" letterSpacing option per 0.5 increment of the letterSpacing value.

But I knew this couldn't be the total story, because the tbOriginal was using a letterSpacing of 0.75, and on screen it was longer than tbCreatedAtRuntime with letterSpacing around 0.5, and shorter than tbCreatedAtRuntime with letterSpacing around 1, and as stated earlier, tbCreatedAtRuntime would treat letterSpacing of 0.75 the same as letterSpacing of 1.0.

What gives?

Fortunately, whilst not intuitive (after all, this is Flash isn't it?), the documentation did this time give me the clue I needed.

It turns out that Flash only supports integer values(1) for letterSpacing for "device fonts". My brain whirred away for a microsecond and I realised what the problem was.

I was using a special font, but I hadn't explicitly told my dynamically-created TextField to use font embedding. I just presumed that, since it got its TextFormat from tbOriginal, it would get the same font embedding as tbOriginal. Not so.

So now I explicitly tell tbCreatedAtRuntime to use the same font embedding as tbOriginal :

tbCreatedAtRuntime.embedFonts = tbOriginal.embedFonts;

... and now at last, letterSpacing works as expected. Whew!




But can you permit me to lament once more just how STUPID this design (or lack of design) is?

Adobe might be good at graphics, but they are very bad at development tools and APIs.

What SHOULD happen is that if ANY text field ANYWHERE in the Flash file has embedded a font, and ANY other text field anywhere else in the same movie (or even created dynamically) attempts to use the same font, the embedded font should be automatically applied to that other text field.

Now, failing that, at the very least, copying the TextFormat from one text field to another should ensure that if the first had an embedded font, the second uses the same embedded font.

Adobe, lift your game! Microsoft's APIs make yours look pathetic. You can do better than this!

(1) The integer-letter-spacing-for-device-fonts limitation is mentioned in the Flash 8 documentation. I'm using Flash 10, and I am surmising that Flash 10 supports 0.5 increments, in contrast to the Flash 8 doco which claims only 1.0 increments are supported in Flash 8.

Flash bugs: dynamic SimpleButton gotcha

I'm creating a SimpleButton in ActionScript and it ain't showing up.

var b:flash.display.SimpleButton = new flash.display.SimpleButton();
b.upState = bla;
b.overState = bla;
b.downState = bla;
b.hitTestState = bla;
b.useHandCursor = true;
this.addChild(b);

The problem is, the button, she no appear. Nada.

I thought maybe my problem is that I'm using the same sprite for the different states, but changing that didn't make any difference.

Turns out, Flash is proving its inferiority once again.

The SimpleButton constructor, it so happens, accepts four OPTIONAL arguments, being the four SimpleButton states.

Given that they are OPTIONAL, you would think you could omit them ALL and just set the four state properties after construction.

You'd think so. And so did I.

But it turns out that, even though the documentation and the in-editor code helps all say the states are optional, THE UP STATE IS ACTUALLY MANDATORY.

Ridiculous.

In short, this works, because it supplies the mandatory-though-pretending-to-be-optional UpState argument to the SimpleButton constructor :

var b:flash.display.SimpleButton = new flash.display.SimpleButton(bla);
/*b.upState = bla; - no longer needed*/
b.overState = bla;
b.downState = bla;
b.hitTestState = bla;
b.useHandCursor = true;
this.addChild(b);

And of course, you might prefer to just save lines and go :

var b:flash.display.SimpleButton = new flash.display.SimpleButton(bla, bla, bla, bla);
b.useHandCursor = true;
this.addChild(b);




On a related note, I was trying to figure out WHY Flash is so STUPID in this regard. (Stupidity and unintuitive behaviour are more common than I would have expected in ActionScript. I really honestly thought Microsoft's XAML was passable and that Adobe would be as good or better. Sadly, Adobe is actually far behind M$ in the 'we make things that actually make sense' game, even if M$ itself isn't perfect.)

My first guess was that the constructor determines the SimpleButton's dimensions from the upState, and thus, when no upState is passed to the constructor, the SimpleButton has no idea how big it needs to be.

If that were the case, I could simply set the SimpleButton's width and height, and it would work.

But no go.

Here's the code :

var b:flash.display.SimpleButton = new flash.display.SimpleButton();
b.width = 100;
b.height = 100;
b.upState = bla;
b.overState = bla;
b.downState = bla;
b.hitTestState = bla;
b.useHandCursor = true;
this.addChild(b);

And it is as dead and useless as the very first code listing in this article.

In short, it seems that the SimpleButton is COMPLETELY UNABLE TO HANDLE UPSTATE BEING OMITTED FROM THE CONSTRUCTOR INVOCATION.

Which makes me ask why Adobe's documentation is so poor that there is no comment about it. And why their compiler doesn't complain when that argument is missing from the constructor invocation. And in fact why, overall, they make such an unintuitive design.

Here's what I would have done, since I believe in making APIs as flexible as possible :

1) All constructor arguments are optional.

2) Button width and height are calculated just-in-time, or at least, calculation is deferred until upState gets set for the first time on a given SimpleButton instance.

Voila! Talk about intuitive! In contrast, I really don't know how Adobe muck up like this, and at multiple places throughout their API. Shame, Adobe. Shame. Please lift your game.