Debugger Console Window with ActionScript parsing

September 23rd, 2008 Victor Posted in advanced, intermediate 4 Comments »

Hi folks,
Been very busy lately but eventually I got the time to write again here. This one, I’m sure, will help some of you quite allot.
Tracing is a very common need for any application developer. It’s so frustrating when you can’t just quickly start a debugging session for the production version of your flash program. There are lots of solutions out there, but each has it’s limitations.

During the years, I developed and fine-tuned my own solution and now, it’s nearly impossible for me to start a new Flash web-app without it. Here are the features of my Debugger Console:

  • the console can be embedded in the production version, you can activate it using a simple javascript command entered in the browsers’ address bar
  • when the Debugger window is not open, all trace log is stored in memory until you choose to open the console, when you can see all of it in the window
  • you can directly type and execute (limited) custom ActionScript code by entering commands in the console input field. The evaluated value of the output of your expression will be printed out. (printing expressions, running function, passing parameters, instantiating (new), assigning, are the main ActionScript constructs that can be parsed by the console
  • command history. Use Up and Down arrow keys inside the console input field to see last used commands

Usage hints:

first type:

javascript:document.embeds[0].debug()

in your browsers’ address-bar (works in Firefox)

You’ll see the console window with all the previous traces listed. You can scroll using the keys or the mouse wheel.

Type a simple expression in the console input field (bottom of the window). For example, type stage and press Enter. Or type help to see a quick help.

To clear console, press the blue button on the top bar once. If you press it twice, the command history will also be cleared.

To close the console, press the red button. You can show it again using the javascript command above. Typically you would like to have this command stored in your bookmarks toolbar.

To assign a  local variable, use:

myVar = "some text"

then you can use your local variable without “local”. simply type myVar and press Enter
Expressions are parsed with regards of type. For example 100+1 will evaluate as 101 and “100″+1 will be 1001

You can execute functions and pass them parameters. Don’t forget to make the useful methods in your application public to be able to access them from the Debugger Console.

You can even create new instances using “new” keyword. Support for “new” keyword is in early stages but it can already be used with a little extra typing. Example:(type the following commands one by one in the console)

obj = new flash.display.Shape()

obj.graphics.lineStyle(0,0,1)

obj.graphics.lineTo(200,200)

stage.addChild(obj)

listDisplay(stage)

To use the console in your web-app, just make the package com.victordramba.debug visible for your project (either by copying the package inside the project source folder or by sharing it using Project Properties -> ActionScript Build Path -> Source Path)

Known bugs and limitations:

  • parsing for single quote (‘) strings is not implemented. Always use double quote (“) to pass strings.
  • succesive binary operators not implemented (you can’t do e.g. 1+2+3)

Security note: Beware, if you embed the console in your production version, it will be available for other people also. Make sure you do not expose sensitive data by your application. Normally, the security wall should be on the server-side, like with any client-server web application. SWF format can be reverse engineered, so all the data inside the flash player can be considered open for the user that received it.

Example: examples/debugger

Download: example.zip

AddThis Social Bookmark Button

ActionScript3 speed test

July 8th, 2008 Victor Posted in advanced, intermediate 4 Comments »

Just read this article about programming language speeds:

Performance Comparison – C++ / Java / Python / Ruby/ Jython / JRuby / Groovy
by Dhananjay Nene

And of course, my first thought – let’s test ActionScript3 in this (a bit arguable) manner

The results were quite surprising, it beats PHP by far:

AS3 (Activex player 9,0,124,0, nondebug): 50 microseconds
AS3 (Stand-alone player, 9.0.115.0, debug): 150 microseconds
PHP (apache module): 600 microseconds
(on the same machine – Core2 Duo 2.4GHz, php running into vmware/debian. If I run the php version in windows, it gets worse :D )

Here is the AS version of the same program.
I compiled it with Flex Builder3, release mode (not debug, that’s a bit slower).

package 
{
	import flash.display.Sprite;
	import flash.text.TextField;
 
	public class speed_test extends Sprite
	{
		public function speed_test()
		{
			var ITER:int = 10000;
			var start:Number = (new Date).getTime(); 
			for (var i:int = 0 ; i < ITER ; i++)
			{
				var chain:Chain = new Chain(40);
				chain.kill(3);
			}
			var end:Number = (new Date).getTime();
 
			var txt:TextField = new TextField;
			txt.width = 300;
			addChild(txt);
			txt.text = "Time per iteration = " + 
				((end - start) / ITER * 1000) + " us.";
		}
	}
}
 
 
class Chain
{
	private var first:Person = null;
 
 
	public function Chain(size:int)
	{
		var last:Person = null;
		var current:Person = null;
		for (var i:int = 0 ; i < size ; i++)
		{
			current = new Person(i);
			if (!first) first = current; 
			if (last)
			{
				last.setNext(current);
				current.setPrev(last);
			}
			last = current;
		}
		first.setPrev(last);
		last.setNext(first);		
	}
 
	public function kill(nth:int):Person
	{
		var current:Person = first;
		var shout:int = 1;
		while(current.getNext() != current)
		{
			shout = current.shout(shout, nth);
			current = current.getNext();
		}
		first = current;
		return current;
	}
 
	public function getFirst():Person
	{
		return first;
	}	
}
 
class Person
{
	private var count:int;
	private var prev:Person = null;
	private var next:Person = null;
 
	public function Person(count:int)
	{
		this.count = count;
	}
 
	public function shout(shout:int, deadif:int):int
	{
		if (shout < deadif) return (shout + 1);
		this.getPrev().setNext(this.getNext());
		this.getNext().setPrev(this.getPrev());
		return 1;
	}
 
	public function getCount():int
	{
		return this.count;
	}
 
	public function getPrev():Person
	{
		return prev;
	}
 
	public function setPrev(prev:Person):void
	{
		this.prev = prev;
	}
 
	public function getNext():Person
	{
		return next;
	}
 
	public function setNext(next:Person):void
	{
		this.next = next;
	}
}
AddThis Social Bookmark Button

AIR: Share the Clipboard Image

March 9th, 2008 Victor Posted in intermediate Comments Off

They just released the AIR goodies for CS3. I guess you already noticed, unless you disabled the auto-update feature of your Adobe software. So, I started to play a bit with it and it proved fast enough for a lazy guy like me. You should know, although I’m completely and hopelessly coder (as opposed to graphic designer) , I’m the type of guy that would never create a Flex project to do a banner. Even if it’s a data driven one. Therefore, I think this CS3 plug-in for AIR is really useful. Add a few buttons, write a few lines (they have to be few, because code completion in Flash sucks) and click the right button. You have your mini desktop application in half an hour. Like this one, that I decided to share with you. It’s my (almost) first. Let’s see what it does:

If you use chat allot, you surely know what I mean. You want to send a screenshot or any image, but you don’t have the file, you just have the bitmap in your Clipboard. Of course, most new chat clients know about file transfer. But you have to open your favourite image editor, paste the image, save the file, browse for it and send. 80% of the cases, I bet you’ll find that your want-to-be-sent-image will just stay at home. Here comes my little program. It displays a tray icon. You click the icon, your Clipboard data is converted to an image format, uploaded on a website and replaced right in the Clipboard with the URL text of your uploaded image, ready to be pasted in the chat. All this in one click. In this example, only the Windows version (trayicon). If you need it, take your time write the mac version.

I used this for uploading, corelib for encoding image and.., no, that’s all.

Ah, almost forgot: the serverside. I used a small PHP script. In real-life, you should limit the usage per IP or use a login system.

here it is: air-shareimage.rar

Note: did not include the corelib files, you should download the lib yourself: corelib

AddThis Social Bookmark Button

Volatile variable scopes

February 8th, 2008 Victor Posted in intermediate Comments Off

This post is not realy about AS3 but more about some basic concepts in Javascript or Actionscript 1,2. The rules also aplies to AS3.

Some people, and I find them quite boring, always use explicit scope, they even refer all variables in the current class by using this.varName or ClassName.varName for statics. They also advocate for not using inner function declarations or anonimus functions. While this seems to be good practice for large projects and team work – making the code more human readable, it surely has it’s downsides. Like polluting the code with long lines, unneeded temporary variable/method names in classes.

Using inner functions and directly passing variables by surrounding scope is often a faster and more economical solution. The solution especially applies when working with events.
Let’s see some code now. How would this timid programmer solve a simple event situation:

   public function addEvent(btn:MovieClip, text:String):void
   {
      //MovieClip is a dynamic class,
      //we can store all cats and dogs inside
      btn.clickText = text;
      btn.addEventListener(Event.CLICK, clickHnd);
   }
 
   private function clickHnd(e:Event):void
   {
      trace(e.target.clickText);
   }

And here’s the nicer way to do this:

   public function addEvent(btn:MovieClip, text:String):void
   {
      btn.addEventListener(Event.CLICK, function(e:Event):void
      {
      	trace(text);
      });
   }

Why is this working? Because the player stores the variable scope along with the anonymous function reference passed to addEventListener. Very nice, it’s transparent for you, you don’t need a new name and an object to pass parameters.
But when using this very nice looking solution, you should know what you’re doing. More precisely, what the player will do. For example, this will not give you the expected result:

   public function addEvents(btnArray:Array):void
   {
      for(var i:uint=0; i < btnArray.length; btnArray.length)
      {
         btnArray[i].addEventListener(Event.CLICK,
         function(e:Event):void
         {
            trace('Button ' + i + ' was cliked');
            //you will get "Button 6 was clicked" for all buttons
         });
      }
   }

One way to do it would be:

   public function addEvents(btnArray:Array):void
   {
   	function fn(i:uint):void
   	{
         btnArray[i].addEventListener(Event.CLICK,
         function(e:Event):void
         {
            trace('Button ' + i + ' was cliked');
         });
   	}
      for(var i:uint=0; i < btnArray.length; btnArray.length)
      	fn(i);
   }

But for situations like this, you should really consider using a storage for the button data. Like a Dictionary (yet another AS3 nice add-on), for example:

   public function addEvents(btnArray:Array):void
   {
      var dic:Dictionary = new Dictionary();
      for(var i:uint=0; i < btnArray.length; i++)
      {
         dic[btnArray[i]] = i;
         btnArray[i].addEventListener(Event.CLICK,
         function(e:Event):void
         {
            trace('Button ' + dic[e.target] + ' was cliked');
         });
      }
   }
AddThis Social Bookmark Button