December 2003 Archives

Merry Christmas

| 1 Comment

Copy and paste the code in Merry_Christmas_2003.as into a new Flash document and publish the movie for a special Christmas greeting. I thought it'd be neat to send out a little Christmas greeting this way instead of posting a .swf directly on my weblog. Courtesy of AsDraw.

Like almost everyone else, I'll be gone until after New Year's. I hope everyone has a safe and happy holiday season, and I'll see you in 2004!

As always, thanks for reading...

"Auto Format" Bug

| 1 Comment

I just found a bug with the "Auto Format" option when editing .as files in the Flash MX 2k4 Pro IDE.

Before asking why I'm using the Flash IDE to edit .as files, let me plead my case. I've been falling in love with PrimalScript for editing of external .as files (both classes and includes), but it doesn't have a "format source" option (at least, not that I can find). I had the need to format some code, and I didn't want to do it manually. Enter the "Auto Format" option in the Flash IDE.

I opened up the .as file in the IDE and hit the "Auto Format" button. A message popped up saying that the script contained syntax errors. Interesting... I clicked on the "Check Syntax" button and confirmed that "The script contains no errors." So now I had to try and isolate the problem. Here's what happened...

The first line of the external .as file looked like this:

class Tokenizer implements /*Serializable,*/ Iterator {

For one reason or another, the "Serializable" interface no longer needed to be implemented for the project. Instead of deleting the reference to it, the code was left in tact but commented out for future consideration. In theory, this shouldn't present a problem... but this is what made "Auto Format" choke.

The bug occurs when an "in-line" comment (/* */) appears in the "implements" list. The syntax for it is correct, but "Auto Format" doesn't know what to do with it. By simply removing the in-line comment (see below), the "Auto Format" functionality worked just fine.

class Tokenizer implements Iterator {

Time to make another bug report...

Breakin' the law...

| 3 Comments

Tonight, I commited an illegal act... I don't think my fiance is going to press charges though.

At this time, I'd like to direct your attention to Exhibit A: Keys locked in ignition.

Upon realizing that the keys were stuck inside, we had a few options. We could've drove to her house for her spare key, but she lives 2 hours away from me. Not very practical. We could've called AAA and had them send out someone to help, but that wouldn't have been fun. We decided to take the third approach - MacGyver style.

At this time, please direct your attention to Exhibits B and C - the FlySwatter-Coat Hanger-Duct Tape approach.


We didn't meet with much success in the above approach. While the FlySwatter was able to get wedged inside the door, it was plastic and didn't provide prying leverage. The duct tape on the end of the coat hanger wasn't working out either - it wasn't as sticky as we hoped it would be, and we had a rough time trying to pull the door lock up with it.

At this point, we needed to break out the real tools. Enter two pairs of pliers. There was enough room to wedge the end of the pliers in the door and provide enough clearance and room to work for the hanger approach again.

Note the big wad of duct tape on the end of the hanger. This approach was not met with success either.

What you don't see pictured is the approach that worked - cooking tongs and a yard stick, in combination with a bent hanger. The tongs provided excellent leverage and enough room to get both the yard stick and the hanger inside the door. By pressing the yard stick and the hanger together, we were able to pull the door lock up. Success!

The only things harmed in breaking into this '98 Toyota Corolla are pictured below. We lost a good yard stick, the tongs busted clear off, the flyswatter head snapped off, a coat hanger was mangled, and some precious duct tape was wasted.

.... a small price to pay for an entertaining Friday night.

Data Validation Tip

| 4 Comments

Anytime you let users input a value that you plan on using in a program you're introducing a chance for something to go wrong. As a programmer, you need to be concerned with making sure that the user enters data you're expecting. When a number is required, what happens if the user enters letter "z"?

Typically, once the user submits their data, some sort of validation is run on it to ensure that the data is acceptable. A simple example looks like this:

search_btn.onRelease = function() {
	var filtered = ""; // save the filtered string
	var current = ""; // current character in keyword
	
	// loop over the keyword text string
	for (var i = 0; i < keywords_txt.text.length; i++) {
		// filter out invalid characters.  The invalid characters
		// are ( ) { } ! @ $ and ^
		current = keywords_txt.text.charAt(i);
		if (current == "(" || current == ")" 
			|| current == "{" || current == "}"
			|| current == "!" || current == "@"
			|| current == "$" || current == "^") {
			// skip over character
		} else {
			// add character to filtered text
			filtered += current;
		}
	}
	
	// display results to output window
	trace(filtered);
}

Is there anything wrong with the above example? It finds any of the invalid characters listed and strips them out of the text entered in the keyword text field. It does what is was supposed to do.. but yet, there's still something wrong with it.

When performing data validation, it's always best to validate data by what characters are accepted, rather than what characters are not accepted. By checking for the characters defined as invalid we allow room for error.

What if I miss a case in the if statement? What if I make a typo and } is replaced with ]? What if another invalid character is discovered later, after the program is already in use? How can I possibly know all of the invalid characters beforehand... and if the list gets long, how can I easily maintain it in the future?

All of those questions can be addressed by simply validating data by a list of allowed characters. No longer do we have to worry about missing an obsure character we might not have thought to exclude, and we don't have to deal with a long list of excludes anymore either. The revised code might look like this:

search_btn.onRelease = function() {
	var filtered = ""; // save the filtered string
	var current = ""; // current character in keyword
	
	// loop over the keyword text string
	for (var i = 0; i < keywords_txt.text.length; i++) {
		// only allow 0-9, a-z, A-Z and space..
		// filter out everything else 
		current = keywords_txt.text.charAt(i);
		if (current >= "a" && current <= "z"
			|| current >= "A" && current <= "Z"
			|| current >= "0" && current <= "9"
			|| current == " ") {
			// add character to filtered text
			filtered += current;
		} 
	}
	
	// display results to output window
	trace(filtered);
}

As you can see, the revised code looks pretty much the same, but is much more powerful at making sure the input is valid. By saying "I'm only allowing these characters" and testing for them, you can improve your data validation routines for user input without worrying about a user "slipping something in" that might go unnoticed.

This approach in general is pretty obvious, but I wanted to point it out as it may not be something you've ever thought about... Always program for the worst-case scenario - your programs will end up being more robust and fault-tolerant in the end.

...need...more...Errors...

| 3 Comments

Has anyone been doing a lot of work with Flash's exception handling? I really applaud Macromedia for implementing exceptions in ActionScript, but I'm a bit disappointed by the lack of exceptions, so to speak. All we get is "Error"? And why is it named "Error" and not "Exception" or "Throwable"?

Borrowing from Java, check out the Throwable class. There are two subclasses - Error and Exception. When you throw something (via the throw keyword in Java), it's of type Throwable, or a subclass thereof, which makes sense.

An Error is usually fatal to the program... Errors are things like "out of memory" that the program should not try to gracefully recover from. Whenever an Error occurs, the program should simply die.

An Exception, on the other hand, is not necessarily fatal to a program. Exception handling is the act of detecting a problem in the program and gracefully resolving it.

So why did Macromedia define Error as the only "throwable" we get in Flash? Look at all of the subclasses of Exception that are available by default in Java. The reason these subclasses are useful is so you can write code like this (pseudo-code):

try {
   someConverstionFunction(string);
} catch (an IllegalArgumentException) {
  // arguments passed to function not valid
} catch (a NumberFormatException) {
  // string could not be converted to number
} catch (some other Exception) {
  // any other Exceptions caught here
}

Exceptions are caught from specific to general (subclass to superclass), and as a programmer you list the specific cases (subclasses) first. If something happens in "someConverstionFunction" - based on the Exception type we know what happened, and we can deal with the different exceptions differently. Maybe there was an extra argument passed in that shouldn't have been (remember, Flash doesn't enforce argument #'s in user-defined functions, that's why we have the "arguments" array). Maybe the string couldn't be converted to a valid number, or maybe something else happened that we weren't expecting. No matter the case, we can write code to handle each individual exception.

In Flash, since all we get is one class for exceptions, we have to implement this functionality on our own by creating a subclass of Error for everything that we can think of that could go wrong... which is annoying coming from a Java background. I've found that in most cases I can simply re-use the pre-packaged exceptions in Java. Rarely have I had the need to create my own exception type, yet in Flash I have to create them all the time.

So.. here's "IllegalArgumentException.as" to give you an idea how to create your own exceptions. Yes, it's very simplistic.. but very useful.

(continue reading...)

'googLinks' updated, code sample

| 4 Comments

I updated my 'googLinks' on the main page to pull the .opml files from my own site instead of getting them from Full as a Goog. I also thought I'd post the code I'm using with the new Tree component in Flash MX 2k4 Pro. It's pretty straightforward, and hopefully my comments will help you understand it a little better...

var categories : Array = ["Central", "ColdFusionMX", "DreamweaverMX", "FlashMX", "WebBuilder"];
var current : Number = 0;
var today : Date = new Date();
var path : String = "/googLinks/";
var cacheBuster : String = "?rand=" + today.getDay();

// single XML variable re-used for every category
var loader : XML = new XML();
loader.ignoreWhite = true;
loader.onLoad = function(success) {
	if (success) {
		// add the head to the tree
		var header = new XML().createElement("node");
		header.attributes.label = categories[current];
		header.attributes.icon = categories[current];

		// keep a reference to the head when we add it
		var treeData = googLinks.addTreeNode(header);
		
		// declare an array to hold all of the links
		//  -- used to sort the entries
		var dataHolder = new Array();
		
		// populate the array with all of the info from the outline
		// tags in the .opml files.
		var body : XMLNode = this.firstChild.firstChild.nextSibling;
		var outline = body.firstChild;
		while (outline != null) {
			dataHolder.push({label:outline.attributes["title"], data:outline.attributes["id"]});
			outline = outline.nextSibling;
		}		
		
		// sort the array, then add the nodes under the head via the
		// 'treeData' reference we created above
		dataHolder.sortOn("label", Array.CASEINSENSITIVE);
		for (var i = 0; i < dataHolder.length; i++) {
			treeData.addTreeNode(dataHolder[i].label, dataHolder[i].data);			
		}
		
		// load the next category if we need to
		if (current < categories.length - 1) {
			current++;
			loader.load(path + categories[current] + ".opml" + cacheBuster);
		} else {
			// nothing else to load... clean up!
			delete loader;
			delete current;
			delete categories;
			delete today;
			delete path;
			delete cacheBuster;
		}
		
	}
}

// start the ball rolling with the first load
loader.load(path + categories[current] + ".opml" + cacheBuster);

// set up the tree style
_global.style.setStyle('themeColor', 'haloOrange');
googLinks.setStyle('selectionColor', 0xFFFFFF);
googLinks.setStyle('rollOverColor', 0xD8D8D8);
googLinks.setStyle('fontFamily', 'Verdana');
googLinks.setStyle('fontSize', 9);
googLinks.rowHeight = 24;

// delcare an icon function to place the icons.  by 
// default I look for the "icon" attribute, and if not
// there, use the 'Bullet' icon.  Every icon has a
// movieClip symbol in the library with its linkage
// name set to the icon name.
googLinks.iconFunction = function (node) {
	var ico = node.attributes.icon;
	if (ico == undefined) {
		ico = 'Bullet';
	}
	return ico;
}

// old school, just declare a changeHandler instead
// of adding an event listener.
googLinks.changeHandler = function () {
	// open up the site if there is a URL
	if (this.selectedNode.attributes.data != undefined) {
		getURL(this.selectedNode.attributes.data);
	} else {
		// no URL, so that means they clicked on a 
		// category head.  if the category is open, 
		// close it, otherwise open it.  the last "true"
		// param is for playing the transition so the
		// the category doesn't just "snap" open or closed
		this.setIsOpen(this.selectedNode, !this.getIsOpen(this.selectedNode), true);
	}
}

Enjoy your weekend! I'll be out playing in the snow. We got hit with around 8 inches overnight here in eastern Pennsylvania... woohoo for the first snow of this winter season! Snowboarding anyone?

Link Stealin' - Goog Style!

| 6 Comments

Rather than trying to update a list of links to weblogs and such, I figured I'd just write a little app that steals them all from Full As a Goog. Check it out on the right under "Links" on the main index page -- (may take a little to load). I used the new tree component from Flash MX 2004 Professional and wrote a little script to parse the .opml files that Full As a Goog has listed in their "blogs on tap" page.

Pretty sweet, huh? Now I don't have to worry about maintaining my own link collection. In the future I should probably put the listing of all of the links in a hidden div in my html code so google will increase everyone's page ranking....

I don't think I can share the .fla because of the EULA and it having the tree component included. I can, however, share the script if you like. I hope I don't suck up too much of the goog's bandwidth though... hehe. Oh great googmaster, let me know if this becomes a problem! :-)

OOP with AS1 officially deprecated

| 9 Comments

Wow, I stumbled across this quote on the Macromedia LiveDocs for Flash MX 2004. Don't hate the messenger, this is straight from the horse's mouth.

The quote below can be found on this page: http://livedocs.macromedia.com/flash/mx2004/main/appx_e_a.htm

"If you have never used ActionScript to write object-oriented scripts and don't need to target Flash Player 5, you should not use the information in this appendix, because writing object-oriented scripts using ActionScript 1 is deprecated; instead, see Creating Classes with ActionScript 2.0 for information on using ActionScript 2.0."

What this means is that Macromedia is really pushing ActionScript 2 syntax. Instead of writing classes like this:

function myClass() {
         // constructor
}
myClass.prototype.myMethod = function() {
          // do stuff here
}

You should adopt the ActionScript 2 syntax and create them like this:

class myClass {
         public function myClass() {
                  // constructor
         }
         
         public function myMethod() {
                  // do stuff here
         }
}

So, if you're still using ActionScript 1 for Object Oriented Programming in content geared for Flash 6 or 7, Macromedia has deprecated the syntax. When syntax is deprecated, this usually means that it will no longer be supported and not guaranteed to work in future versions. Note that using prototypes is not deprecated, but defining classes via the prototype is.

I'm wondering if the deprecation is to get everyone on board with the same syntax now, or if Macromedia is planning on abandoning the prototype model behind-the-scenes completly? Maybe a combination of both? Maybe some entirely different reason? I doubt they'll re-write how classes are implemented behind-the-scenes in the Flash Player, and I don't think the prototype is ever going away (nor should it). I think that this is just a push to make sure everyone is using the latest and greatest syntax, but this is just my opinion.

Have you switched yet?

Flex.org - The Directory for Flex

Archives