Web app to extract torrent files out of Blizzard Downloader

Diablo 3 was announced today and like many thousands of other gamers online right now I’m trying to download the 800mb high def gameplay trailer while putting up with the very clumsy Blizzard Downloader application. For those who don’t know, the Blizzard Downloader is just a mini BitTorrent client with a single torrent file baked in. I’m not a big fan of the downloader because I already have a BitTorrent client that’s much better at bandwidth allocation and my firewall’s already set up for that client. I’d much rather download the movie with my own client instead of Blizzards so I’ve written a little flash app to help facilitate that.

To use this, just point the app at the url of any Blizzard Downloader exe file online (I’m not sure if it’ll work with the .dmg files) and hit the ‘Extract’ button. A link will pop up below that you can click to save the torrent file. The file has no name by default so you’ll have to rename it ‘whatever.torrent’ after it finishes downloading. The resulting torrent will still connect to Blizzards tracker and you’ll download the same file you would be if you were using the Blizzard Downloader app.

This should work with all browsers other then IE 7 and below, since IE doesn’t support the data:URI scheme to create dynamic files.


View Source

Example URLs:
Diablo 3 Gameplay Downloader
Starcraft 2 Gameplay Downloader

More Info:
Blizzard Downloader Wiki

Introducing GUIMark - An RIA benchmark for Flex, Silverlight, HTML and more

If you’re wondering why I’ve been quiet the past few weeks it’s because I’ve been devoting most of my free time to finishing off a new benchmark I’m releasing today called GUIMark. GUIMark is kinda like an Acid3 test on speed that’s geared towards RIA technologies. The goal was to figure out how to implement a reference design in different runtimes and then benchmark how smoothly that design could be animated. So far I have implementations in DHTML, Flex, Java, Silverlight 1 and Silverlight 2. All the results and and implementation details can be found under the GUIMark page.

GUIMark shares alot in common with another RIA benchmark Bubblemark. I’ve written a bit about Bubblemark and why I think an alternative is necessary, but I do believe Bubblemark and GUIMark can coexist while serving 2 different purposes. Alexey Gavrilov stated it best in that he sees Bubblemark as a sortof ‘Hello World’ launchpad into comparing different environments and I agree with him. Bubblemark is a *very* accessible test suite and its easy for any kind of developer to jump in and play around with performance techniques. GUIMark takes a different approach by trying to benchmark the types of UI elements common in our Web 2.0 world. This includes things like vector redraws, alpha transparencies, text reflow, bitmap motion, and 9 scale slicing rules. From there I just fill up the render pipeline until it becomes so over-saturated that it becomes easy to visually distinguish which rendering engines are more efficient then others. As a result, the benchmark is more complicated on a visual level and requires a bit more time then Bubblemark to understand the implementation rules. Lastly with GUIMark I’ve tried to get into some of the lower level details behind how rendering engines work and how that’s affected the creation of this project.

I’m hoping that developers and designers will be able to use this test suite to identify any pros or cons to choosing a particular environment when visual transitions are a key element of the experience. I’m also hoping these benchmarks provide a spotlight for the community that we can turn toward the runtime engineers inside Sun or Adobe or Mozilla to demand better performance.

Go to GUIMark home page

Kick starting the garbage collector in Actionscript 3 with AIR

During the final months of my work with eBay Desktop, my sights were set squarely on optimization, both memory and cpu. When it came time to start messing with the garbage collector, my sanity went from bad to worse. What I originally thought was going to be a straightforward way of releasing memory in AIR turned into a 2 month long testcase with some discouraging outcomes.

Memory usage in eBay Desktop was something that always lingered in the back of my mind during the entire development cycle. Because of the shifting nature of our requirements, the issue was only explored near the end, even though we knew in the beginning that memory usage had to go through valleys and peaks in a managed way while users spent time in it throughout the day. We had alerts that would open and close, we had an app that would run in the system tray, and we considered making a ‘lite’ mode that would sit on top of your desktop all day, each of which had different memory requirements. In the beginning we used a well known hack to test garbage collection until part way through the development of AIR and Flex 3 Adobe finally added support for calling the garbage collector directly. We knew at this point we had a viable route for managing memory since Adobe was now making the effort to acknowledge the need. So now all that was required was a simple call to

flash.system.System.gc()

and we were set to go….right?

Well, not exactly. First off we learned that a call to System.gc() only does a mark OR a sweep on any given object, but not both in the same call. So in order to have the effect of releasing memory back to the OS, we needed to call it twice in a row. One call to mark any dereferenced objects and sweep away old marks, and the second to now sweep away marks from the first call.

flash.system.System.gc();
flash.system.System.gc();

Now this seemed to be releasing memory back with pretty basic test cases, but it wasn’t working under production scenarios and we had to turn to Adobe engineers to help with the problem. What we learned was that you have to contend with 2 different kinds of pointers when working in AS3; pointers that exist in bytecode, and pointers that *may* exist in the Flash player itself that you’d never know about. What I started to realize was that the Flash player was never really engineered to be aggressive about memory usage. It was designed to plug memory leaks and manage memory plateaus, but not designed with an assumption that users would be interested in lowering those plateaus. It makes sense because most Flash content is viewed in the browser for a short amount of time before the plugin is destroyed and all memory is released when a user navigates away. With AIR, the rules changed since users are more conscience of discreet application memory usage and applications might not always need the same memory when launched vs after 2 hours of usage.

First up we found that the Flash player was always maintaining a reference to the last Sprite clicked, so if you destroyed an AIR window that the users had interacted with, you couldn’t get garbage collection to work until interacting with another window, which can become a big problem if you’re running in system tray mode and there are no windows to click in. Secondly we learned that you have to push any existing enterframe handler off the call stack by creating a new one. Adobe took care of the first problem, but to handle the second one we had to change our GC call a bit.

private var gcCount:int;
private function startGCCycle():void{
	gcCount = 0;
	addEventListener(Event.ENTER_FRAME, doGC);
}
private function doGC(evt:Event):void{
	flash.system.System.gc();
	if(++gcCount > 1){
		removeEventListener(Event.ENTER_FRAME, doGC);
	}
}

Another facet we hadn’t considered was the affects of the Flex framework on garbage collection. Flex kept some of the same design philosophy as the player itself, mainly that end users were loading applications in the browser and then navigating away when done. Garbage collection was therefore considered on a micro level involving user components, but not at the framework level which could be guaranteed to exist throughout the life of the app. Adobe made strides on patching the framework to work better in discreet Windows, but ultimately some things couldn’t be changed. What we found was that CSS could not be defined in any <mx:Window> component. It had to be defined in the root <mx:WindowedApplication> which would take care of declaring CSS globally for all windows. Also we were forced to clear some global variables ourselves, which caused our code to now look like this.

private var gcCount:int;
private function startGCCycle():void{
	ContainerGlobals.focusedContainer = this;
	gcCount = 0;
	addEventListener(Event.ENTER_FRAME, doGC);
}
private function doGC(evt:Event):void{
	flash.system.System.gc();
	if(++gcCount > 1){
		removeEventListener(Event.ENTER_FRAME, doGC);
	}
}

Lastly, not all features in AIR could be unhooked with our enterFrame trick, after another couple days of testing we found components that needed to be unhooked with Timers like the HTML component. One last tweak to our garbage collection cycle and we were home free.

private var gcCount:int;
private function startGCCycle():void{
	gcCount = 0;
	addEventListener(Event.ENTER_FRAME, doGC);
}
private function doGC(evt:Event):void{
	flash.system.System.gc();
	if(++gcCount > 1){
		removeEventListener(Event.ENTER_FRAME, doGC);
		setTimeout(lastGC, 40);
	}
}
private function lastGC():void{
	flash.system.System.gc();
}

We were now able to successfully garbage collect any objects that have been dereferenced in Flash. We had three things we had to look out for in the app now.

  1. All display objects that added listeners on to model data had to be weakly referenced or they wouldn’t be automatically dereferenced. This is because our architecture kept model data alive while individual window stages were being destroyed. I feel like I should point out that contrary to some beliefs, it is not a good idea to apply weak references by default throughout your entire app. Trust me when I say that its alot easier to debug an application with memory leaks due to strong listeners, then it is to debug an app in which users report random failures because underneath the hood weakly referenced objects are getting accidentally destroyed when the GC kicks in. You can never avoid bugs, so you should program in a way that makes them consistent to find.
  2. All asynchronous events needed to be explicitly shut down. This included Timers, Loaders, File and DB transactions. Setting these to be weakly referenced is not enough as all asyncronous objects in AS3 register themselves to the Flash player while they are running. It is impossible to access objects that have been dereferenced in code but continue to be referenced by the player like a running timer.
  3. No anonymous closures allowed.

After all this was taken care of we began to learn that garbage collecting objects in Flash didn’t translate so easily to releasing memory back to the OS. If you ever look at the memory graph in the Flex debugger and then open up the Task Manger or Activity Monitor to compare memory usage, you’ll notice a huge disparity between the two.

Flex Builder memory profiler
FlexBuilder reports only 15mb of AS3 object data

AIR system memory profile
AIR private memory really takes up 65mb on the system

The difference you’re seeing is Object Memory vs. Rendering Memory and the bulk of all memory used by the Flash player goes toward rendering. Displaying an empty stage in Flash can take up anywhere between 10mb and 20mb depending on the width and height and then it climbs by roughly 4k for each display object attached to the stage. This can add up quickly when using the Flex framework where even a simple button uses several display objects.

What we ultimately found was that even though we could successfully release AS3 objects, we couldn’t reliably get the Flash player to release render data. So an app that started at 20mb would climb to 100mb, and when the entire stage was destroyed, we’d go back down to only 80mb. You can actually test this for yourself by downloading a sample Flex 3 project and observing the effects. What I’ve learned from Adobe is that the player ends up fragmenting memory quite a bit. It probably goes back to the heart of the initial design of the Flash player I described above. All the effort was put into making a killer GUI environment that deferred memory management to whether the browser window was open or not, and as a result the memory system was not optimized for more aggressive use cases. I can only guess the problem comes from the fact that AS3 code is attached to the timeline of the player itself, and managed by the elastic racetrack. As a result both AS3 objects and render data get mixed in to the same memory page, and releasing just the render data doesn’t matter when model data is placed on the same page.

Adobe has assured me they are working on the problem but it realistically won’t make it in until after AIR 2.0, and its unclear whether those fixes will be merged into the the plugin player given that the need isn’t very high for web pages. Until then, you can not count on creating an application in AIR that releases memory back to the OS. The best approach is to reuse the smallest amount of displayobjects possible to achieve the desired workflow. Get used to adding and removing children without destroying them but instead sliding them off into a pool for later reuse, as this helps keep the memory plateau low during use.

Hacking width and height properties into Flex’s CSS model

As much as I love working with the Flex layout model, in many ways it feels inferior to its HTML cousin. I’ll take Flex’s container components over HTML tables and divs any day, but I’ve always been disappointed with the fairly weak CSS model found in Flex. From an architectural level the framework decisions makes sense and keeps internal logic fast and clean, but from an implementation standpoint, it becomes an annoying roadblock. Heres a quick example of the problem.

<mx:Style>
	.navItem {
		vertical-align: middle;
		corner-radius: 5;
		border-style: solid;
		border-color: #F3CB19;
		background-color: #A87500;
	}
</mx:Style>
<mx:HBox styleName="navItem" height="30"/>
<mx:HBox styleName="navItem" height="30"/>
<mx:HBox styleName="navItem" height="30"/>

In this case, since height is a class property, it must be defined on the HBox instance and can’t be moved into CSS. It makes the code less manageable and adds restrictions to changing themes at runtime.

In order to define class properties with CSS we need to break some of the framework rules. Since we can’t have class metadata defining a value as both a CSS and a class property, we need to leave all metadata as-is, and ‘foward’ the css definitions on to the class. In practical terms what this means is that changing the height in css will change the height on the component, but changing the height directly on the component wont update the css definition. The code below illustrates how this plays out inside a custom component.

package com.craftymind.controls
{
	import mx.containers.HBox;
	import mx.styles.StyleManager;

	public class extHBox extends HBox
	{
		override public function styleChanged(styleProp:String):void{
			super.styleChanged(styleProp);
			if(!styleProp || styleProp == "styleName"){ //if runtime css swap or direct change of stylename
				var classSelector:Object = StyleManager.getStyleDeclaration("." + styleName);
				if(classSelector != null){
					applyProperties(classSelector, ["width", "height", "percentWidth", "percentHeight", "x", "y", "visible"]);
				}
			}
		}
		private function applyProperties(styleObj:Object, arr:Array):void{
			for each (var item:String in arr){
				var prop:Object = styleObj.getStyle(item);
				if(prop != null) this[item] = prop;
			}
		}
	}
}

When the HBox detects that the styleName or runtime definition has changed, it scans the classSelector for width, height, x, y and visible properties to be applied. You can add whatever properties you want in there including text labels or image sources depending on the component being extended. I haven’t fully tested it so I’m not sure if type selectors work, and I know that calling obj.setStyle(”height”, 10); definitely wont work, but your better off calling obj.height = 10 in that case anyway.

Heres a complex menu system controlled completely with css including y positioning, height changes, and header visibility.


View Source

We now have separation of content from style thats alot closer to what HTML offers, and as a bonus, all property-based databinding continues to work on the values passed through CSS.

<cm:extHBox styleName="header">
	<mx:Label text="Header Text"/>
</cm:extHBox>
<cm:extHBox id="nav" styleName="navContainer">
	<cm:extHBox styleName="navItem">
		<mx:Label text="Nav Item 1"/>
	</cm:extHBox>
	<cm:extHBox styleName="navItem">
		<mx:Label text="Nav Item 2"/>
	</cm:extHBox>
	<cm:extHBox styleName="navItem">
		<mx:Label text="Nav Item 3"/>
	</cm:extHBox>
</cm:extHBox>
<mx:Button label="Switch CSS" click="switchCSS()" y="{nav.y+nav.height+2}"/>
.header {
	background-color: #000000;
	border-style: solid;
	border-color: #FFFFFF;
	border-thickness: 2;
	color: #FFFFFF;
	x: 0;
	y: 0;
	percent-width: 100;
	height: 20;
	visible: true;
}
.navContainer {
	background-color: #000000;
	border-style: solid;
	border-color: #FFFFFF;
	border-thickness: 2;
	vertical-align: bottom;
	horizontal-align: left;
	padding-left: 3;
	x: 0;
	y: 20;
	percent-width: 100;
	height: 50;
}
.navItem {
	vertical-align: middle;
	corner-radius: 5;
	border-style: solid;
	border-sides: "left top right";
	border-color: #FFFFFF;
	border-thickness: 2;
	background-color: #000000;
	padding-left: 3;
	padding-right: 3;
	color: #FFFFFF;
	height: 30;
}

Image smoothing in Flex

The Flex Image control doesn’t expose Bitmap smoothing by default but can easily be added in through subclassing the component. Smoothing is a nice feature for removing jaggies from images that have been scaled either up or down, and in practice hasn’t caused any noticable cpu hangups to do the post processing. I’m writing up a patch to submit to the Flex Open Source initiative, but in the meantime, heres a quick and dirty hack to enable it in the Flex 2 and Flex 3 SDK.

Create a new MXML component and name it SmoothImage.mxml, then add the following code.

<?xml version="1.0" encoding="utf-8"?>
<mx:Image xmlns:mx="http://www.adobe.com/2006/mxml">
	<mx:Script>
		<![CDATA[
			import flash.display.Bitmap;
			override protected function updateDisplayList(unscaledWidth:Number,unscaledHeight:Number):void{
				super.updateDisplayList(unscaledWidth, unscaledHeight);
				if(content is Bitmap){
					var bmp:Bitmap = Bitmap(content);
					if(bmp && bmp.smoothing == false){
						bmp.smoothing = true;
					}
				}
			}
		]]>
	</mx:Script>
</mx:Image>

Now just use <local:SmoothImage source=”myimage.jpg”/> the same way you’d use a normal image component and you’re all set. This code will take care of smoothing both dynamically loaded images as well as embedded images in one simple script. It also handles broken images gracefully. Heres a quick sample showing the affects of scaling the Google logo with and without smoothing.

SmoothImage test case


And the code used to create this…

<!-- Top Images -->
<mx:Image source="{googlelogo}" width="60" height="25"/>
<mx:Image source="{googlelogo}" width="200" height="90"/>
<mx:Image source="{googlelogo}" width="400" height="180"/>

<!-- Bottom Images -->
<local:SmoothImage source="{googlelogo}" width="60" height="25"/>
<local:SmoothImage source="{googlelogo}" width="200" height="90"/>
<local:SmoothImage source="{googlelogo}" width="400" height="180"/>

Actionscript 3.0 prototyping, viable but costly

Back in the Flash 6 – Flash 8 world, I was a big fan of prototyping, mostly because of the limitations of MovieClip inheritance. I haven’t needed to use it at all in Actionscript 3 but I was still curious about how to accomplish it nowadays. Here’s the example I was able to create in Flex.

Sprite.prototype.spriteHelper = new SpriteHelper();
Sprite.prototype.rotateTo = function(deg:int):void{
	var sh:SpriteHelper = this["spriteHelper"];
	sh.target = this;
	sh.rotateTo(deg);
}
package
{
	import flash.display.Sprite;
	import flash.events.TimerEvent;
	import flash.utils.Timer;

	public class SpriteHelper
	{
		public var _degreeTo:int = 0;
		public var _degCount:int = 0;
		public var _degTimer:Timer = null;
		public var target:Sprite;
		public function rotateTo(deg:int):void{
			_degreeTo = deg;
			_degCount = 0;
			_degTimer = new Timer(10);
			_degTimer.addEventListener(TimerEvent.TIMER, doAnimateRotation);
			_degTimer.start();
		}
		public function doAnimateRotation(event:TimerEvent):void{
			_degCount++;
			if(_degCount <= 40){
				target.rotation = _degreeTo * (_degCount/40);
			}else{
				_degTimer.removeEventListener(TimerEvent.TIMER, doAnimateRotation);
				_degTimer = null;
			}
		}
	}
}
<mx:Box id="myContainer" backgroundColor="#FF0000" width="100" height="100" right="40" y="0" creationComplete="myContainer['rotateTo'](50)"/>

You’ll notice 2 things in the implementation here. Since Sprite is a statically defined class, accessing the prototype chain requires bracket syntax ala myContainer[‘rotateTo’](50), and secondly, most of the functionality of rotateTo has been moved into a separate class. The reason for the latter point is because accessing the prototype chain is costly, as it has to recurse through the inheritance chain until it finds the class with the property. As a result I’ve limited the prototype lookups to just spriteHelper and I move all the functionality into there.

Another thing I found in the docs is that every class creates a prototype chain by default, so merely adding prototype definitions has no effect on the creation of that object.

Find as you type sorting on large record sets

One of the sorting methods I’ve been working on this week is implementing a fast find as you type method for close to 30,000 records in AS3. The feature works exactly like iTunes library search, just with a lot more data (unless you’re rocking 1800 hours worth of music). The only rule with implementing this kind of feature is that it has to feel instant to the end user, otherwise we’ll have to switch to a Find-after-pressing-search method.

Setup
The records are stored locally as a flat xml structure.

<entry id="20081" name="Antiques" fullName="Antiques" />
<entry id="37903" name="Antiquities (Classical, Amer.)" fullName="Antiques|Antiquities (Classical, Amer.)" />
<entry id="37905" name="Egyptian" fullName="Antiques|Antiquities (Classical, Amer.)|Egyptian" />
<entry id="37906" name="Greek" fullName="Antiques|Antiquities (Classical, Amer.)|Greek" />
<entry id="37907" name="Roman" fullName="Antiques|Antiquities (Classical, Amer.)|Roman" />

The data is then loaded in as an XMLList and bound to a datagrid. From there, searches should match keywords in the fullName attribute and the datagrid will show only the entries matched.

Method #1 - Iteration
There are 2 ways to iterate the search, either use AS3’s built in E4X expressions to generate unique xml lists, or use collection filtering on the existing list. The first method flexes the power of E4X expressions, but takes a hit on swapping out the datagrid with a new dataprovider, the second works on the existing dataprovider but lacks any indexing power xml might provide.
E4X expression filtering

filteredXMLList = rawXMLList.(@fullName.indexOf(searchTerm) > -1);

Filter Time: 200 ms
Collection Filtering

filteredXMLListCollection = new XMLListCollection(rawXMLList);
filteredXMLListCollection.filterFunction = collectionFilter;
private function collectionFilter(item:XML):Boolean{
	return item.@fullName.indexOf(searchTerm) > -1;
}

Filter Time: 300-200 ms
Using E4X expressions is more powerful then filtering, but the total time for both methods still feels sluggish in the UI.

Method #2 - Pattern matching full text.
Again, there are 2 approaches to pattern matching strings in AS3, RegExp and String.indexOf(). The idea is to apply pattern matching on the raw string representation of the xml to create a new xml string containing only the nodes matched. The new string is then cast back into an XMLList to be placed in the datagrid.
RexExp matching

var pattern:RegExp = new RegExp("<[^<]*" + searchTerm + "[^>]*>", "ig");
var result:Array = rawXMLString.match(pattern);
filteredXMLList = new XMLList(result.join(""));

Filter Time: 31000-14000 ms (31-14 seconds)

IndexOf matching

private function searchStringFor(source:String, term:String):String{
	var lowersource:String = source.toLowerCase();
	var lowerterm:String = term.toLowerCase();
	var i:Number = 0;
	var out:String = "";
	var pos:Number = 0;
	while(i > -1){
		pos = lowersource.indexOf(lowerterm, i);
		if(pos > -1){
			out += source.substring(source.lastIndexOf("<", pos), source.indexOf(">", pos)+1);
			i = pos+term.length;
		}else{
			i = pos;
		}
	}
	return out;
}
filteredXMLList = new XMLList(searchStringFor(rawXMLString, searchTerm));

Filter Time: 200-50 ms

While the RegExp and indexOf are performing the same match, RegExp clearly has a long way to go before being viable in AS3. Even using simply pattern matches with String.search() during Method #1 above was 3 times slower then an indexOf during iteration. IndexOf in Method #2 on the other hand has gotten us down to a 200-50 ms filter time. 50 ms is decent but 200 ms still feels slow.

Final Method - Key search + reference copy
At this point, indexOf searches on the full string block appear to be the fastest way of filtering, and it provides the most room for refinement. Two aspects are contributing to the slowdown at this point: 1. unneccessarily searching the full xml structure, 2. constructing a new xml string and casting it to XMLList after each search. We can cover both issues by initially loading the xml string into an XMLList and iterating that list to generate a second string containing just the fullName field and the index that fullName belongs to in the original XMLList

rawXMLList = XMLList(urlLoader.data);
var count:int = 0;
for each(var node:XML in rawXMLList){
	fullNameIndex += node.@fullName.toLowerCase() + "<" + count + ">";
	count++;
}

This will generate a string looking like

Antiques<0>
Antiques|Antiquities (Classical, Amer.)<1>
Antiques|Antiquities (Classical, Amer.)|Egyptian<2>
Antiques|Antiquities (Classical, Amer.)|Greek<3>
Antiques|Antiquities (Classical, Amer.)|Roman<4>

Now when we do an indexOf search on the above string, we can look ahead to the index inside the < > tags to find which reference in the original rawXMLList to use. Those references are then set into a new XMLList to display.

private function searchStringInAttribute(list:XMLList, attributelist:String, term:String):XMLList{
	var output:XMLList = new XMLList();
	var i:Number = 0;
	var pos:Number = 0;
	var index:int = 0;
	var count:int = 0;
	while(i > -1){
		pos = attributelist.indexOf(term, i);
		if(pos > -1){
			index = int( attributelist.substring(attributelist.indexOf("<", pos)+1, attributelist.indexOf(">", pos)) );
			output[count] = list[index];
			count++;
			i = pos+term.length;
		}else{
			i = pos;
		}
	}
	return output;
}
filteredXMLList = searchStringInAttribute(rawXMLList, fullNameIndex, searchTerm.toLowerCase());

Filter Time: 70-10 ms

These filtering times are excellent and feel extremely smooth. I was a bit surprised to see that performing an indexOf search on a large block of text like this, then looking for the XMLList key in string form, was faster then performing a search inside an array iteration and mapping the array key to the XMLList key. The final source is listed below.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()">
	<mx:Script>
		<![CDATA[
			import flash.utils.getTimer;

			[Bindable]
			private var filteredXMLList:XMLList;
			private var rawXMLList:XMLList;
			private var fullNameIndex:String;
			private var urlLoader:URLLoader;

			private function init():void{
				urlLoader = new URLLoader();
				urlLoader.addEventListener(Event.COMPLETE, entriesLoaded);
				urlLoader.load(new URLRequest("entryList.xml"));
			}
			private function entriesLoaded(e:Event):void{
 				rawXMLList = new XMLList(urlLoader.data);
 				var count:int = 0;
 				var node:XML;
 				for each(node in rawXMLList){
 					fullNameIndex += node.@fullName.toLowerCase()+"<"+count+">";
 					count++;
 				}
 				applyFilter();
 				urlLoader.removeEventListener(Event.COMPLETE, entriesLoaded);
 				urlLoader = null;
			}
			private function searchStringInAttribute(list:XMLList, attributelist:String, term:String):XMLList{
				var output:XMLList = new XMLList();
				var i:Number = 0;
				var pos:Number = 0;
				var index:int = 0;
				var count:int = 0;
				while(i > -1){
					pos = attributelist.indexOf(term, i);
					if(pos > -1){
						index = int( attributelist.substring(attributelist.indexOf("<", pos)+1, attributelist.indexOf(">", pos)) );
						output[count] = list[index];
						count++;
						i = pos+term.length;
					}else{
						i = pos;
					}
				}
				return output;
			}
			private function applyFilter():void{
				if(filtertext.text.length < 2){
					filteredXMLList = rawXMLList;
				}else{
					var searchTerm:String = filtertext.text;
					var s:int = getTimer();
					filteredXMLList = searchStringInAttribute(rawXMLList, fullNameIndex, filtertext.text.toLowerCase());
					trace("filter time: "+(getTimer()-s));
				}
			}
		]]>
	</mx:Script>
	<mx:VBox width="100%" height="100%">
		<mx:TextInput id="filtertext" width="200" keyUp="applyFilter()"/>
		<mx:DataGrid id="category_list" width="100%" height="100%" dataProvider="{filteredXMLList}">
			<mx:columns>
				<mx:DataGridColumn id="dateCol" dataField="@id" headerText="Category ID" width="100"/>
				<mx:DataGridColumn id="titleCol" dataField="@name" headerText="Category Name"/>
				<mx:DataGridColumn id="idCol" dataField="@fullName" headerText="Category Path"/>
			</mx:columns>
		</mx:DataGrid>
	</mx:VBox>
</mx:Application>