You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by ah...@apache.org on 2014/04/25 08:33:23 UTC

[41/42] TourDeFlex donation from Adobe Systems Inc

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/3dc107b9/TourDeFlex/TourDeFlex/src/classes/LocalQuickStart.as
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex/src/classes/LocalQuickStart.as b/TourDeFlex/TourDeFlex/src/classes/LocalQuickStart.as
new file mode 100644
index 0000000..3e44e8b
--- /dev/null
+++ b/TourDeFlex/TourDeFlex/src/classes/LocalQuickStart.as
@@ -0,0 +1,159 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package classes
+{
+	/********************************
+	 * This class has been deprecated	
+	*********************************/
+	
+	
+	import flash.events.Event;
+	import flash.events.IOErrorEvent;
+	import flash.filesystem.File;
+	import flash.filesystem.FileMode;
+	import flash.filesystem.FileStream;
+	import flash.net.SharedObject;
+	import flash.net.URLLoader;
+	import flash.net.URLRequest;
+	import flash.system.Capabilities;
+	
+	public class LocalQuickStart
+	{
+		
+		//--------------------------------------------------------------------------
+		//  Variables
+		//--------------------------------------------------------------------------			
+		public static var url:String = "quickstart.html";
+		
+		private static var cookieName:String = "TourDeFlex";
+		private static var onlineVersion:String = "";
+		private static var localLanguage:String = "en";
+		private static var onlineVersionUrl:String = "";
+		
+		
+		//--------------------------------------------------------------------------
+		//  Load/setup
+		//--------------------------------------------------------------------------	
+		public function LocalQuickStart()
+		{
+		}
+		
+		public static function update():void
+		{						
+			var staticContainerPath:String = "data/";
+			var updatableFile:File = File.applicationStorageDirectory.resolvePath(url);
+			var staticFile:File = File.applicationDirectory.resolvePath(staticContainerPath + url);	
+					
+			localLanguage = Capabilities.language.toLowerCase();
+			//localLanguage = "jp";
+			
+			if(localLanguage != "en")
+			{
+				var newUrl:String = Config.appendLanguage(url, localLanguage);
+				var newStaticFile:File = File.applicationDirectory.resolvePath(staticContainerPath + newUrl);
+				if(newStaticFile.exists)
+					staticFile = newStaticFile;
+			}
+
+			if(Config.isAppFirstTimeRun() || !updatableFile.exists)
+				staticFile.copyTo(updatableFile, true);
+				
+			url = updatableFile.url;
+			
+			checkForNewLocalQuickStart();
+		}
+		
+		//--------------------------------------------------------------------------
+		//  Helper/shared functions
+		//--------------------------------------------------------------------------		
+		private static function checkForNewLocalQuickStart():void
+		{
+			var loader:URLLoader = new URLLoader(new URLRequest(Config.QUICK_START_LOCAL_UPDATER_URL));
+			loader.addEventListener(Event.COMPLETE, updaterXmlLoaded);
+			loader.addEventListener(IOErrorEvent.IO_ERROR, updaterXmlLoadedError);
+		}
+		
+		private static function updaterXmlLoadedError(event:IOErrorEvent):void
+		{
+		}
+				
+		private static function updaterXmlLoaded(event:Event):void
+		{
+			var loader:URLLoader = URLLoader(event.target);
+			var updaterXml:XML = new XML(loader.data);
+			
+			var currentVersion:String = "0";
+			var cookie:SharedObject = SharedObject.getLocal(cookieName);			
+			if(cookie.data.localQuickStartVersion != null)
+				currentVersion = cookie.data.localQuickStartVersion;
+			
+			onlineVersion = updaterXml.version;
+			var onlineVersionDescription:String = updaterXml.description;			
+			
+			if(onlineVersion > currentVersion)
+			{
+				onlineVersionUrl = updaterXml.url;
+				downloadNewVersion(onlineVersionUrl);
+				if(onlineVersionDescription.length > 0)
+				{
+					// Only show notice if a description was provided, otherwise, silent install
+					//Alert.show(onlineVersionDescription, "Updated to Version " + onlineVersion);
+				}
+			}
+		}
+		
+		private static function downloadNewVersion(path:String):void
+		{
+			if(localLanguage != "en")
+				path = Config.appendLanguage(path, localLanguage);
+			
+			var loader:URLLoader = new URLLoader(new URLRequest(path));
+			loader.addEventListener(Event.COMPLETE, updatedVersionLoaded);	
+			loader.addEventListener(IOErrorEvent.IO_ERROR, updatedVersionLoadingError);
+		}
+		
+		private static function updatedVersionLoadingError(event:IOErrorEvent):void
+		{
+			var loader:URLLoader = new URLLoader(new URLRequest(onlineVersionUrl));
+			loader.addEventListener(Event.COMPLETE, updatedVersionLoaded);	
+			loader.addEventListener(IOErrorEvent.IO_ERROR, updatedVersionLoadingError);			
+		}
+		
+		private static function updatedVersionLoaded(event:Event):void
+		{
+			var file:File = File.applicationStorageDirectory;
+			file = file.resolvePath(url);
+			if(file.exists)
+				file.deleteFile();
+
+			var loader:URLLoader = URLLoader(event.target);
+
+			var fileStream:FileStream = new FileStream();
+			fileStream.open(file, FileMode.WRITE);
+			fileStream.writeUTFBytes(loader.data);
+			fileStream.close();		
+			
+			var cookie:SharedObject = SharedObject.getLocal(cookieName);
+			cookie.data.localQuickStartVersion = onlineVersion;
+			cookie.flush();		
+		}		
+		//--------------------------------------------------------------------------
+		//--------------------------------------------------------------------------	
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/3dc107b9/TourDeFlex/TourDeFlex/src/classes/ObjectData.as
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex/src/classes/ObjectData.as b/TourDeFlex/TourDeFlex/src/classes/ObjectData.as
new file mode 100644
index 0000000..e9125fd
--- /dev/null
+++ b/TourDeFlex/TourDeFlex/src/classes/ObjectData.as
@@ -0,0 +1,336 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package classes
+{
+	import flash.desktop.NativeApplication;
+	import flash.events.Event;
+	import flash.events.IOErrorEvent;
+	import flash.filesystem.File;
+	import flash.filesystem.FileMode;
+	import flash.filesystem.FileStream;
+	import flash.net.URLLoader;
+	import flash.net.URLRequest;
+	
+	import mx.collections.ArrayCollection;
+	import mx.collections.Sort;
+	import mx.collections.SortField;
+	import mx.collections.XMLListCollection;
+	import mx.controls.Alert;
+	import mx.managers.CursorManager;
+	
+	import plugin.Component; //HS
+	
+	public class ObjectData
+	{		
+		//--------------------------------------------------------------------------
+		//  Variables
+		//--------------------------------------------------------------------------
+		[Bindable] public var topLevelCategoriesXml:XMLList;		
+		[Bindable] public var listXml:XMLListCollection;
+		[Bindable] public var treeXml:XMLListCollection;
+		[Bindable] public var featuredTreeXml:XMLListCollection;		
+		[Bindable] public var searchTags:Array;
+		private var objectXml:XML;
+		private var selectedTopLevelCategory:String = "";
+		private var previousSortType:String;
+
+		//--------------------------------------------------------------------------
+		//  Loading/setup
+		//--------------------------------------------------------------------------		
+		public function ObjectData()
+		{		
+			loadData();
+		}
+		
+		public function loadData():void
+		{
+			var objectsUrl:String = Config.OBJECTS_URL;
+			trace(objectsUrl);
+			var updatableObjectFile:File = File.applicationStorageDirectory.resolvePath(Config.OBJECTS_FILE);
+			var staticObjectFile:File = File.applicationDirectory.resolvePath(Config.OBJECTS_URL);
+					
+			if(Config.isAppFirstTimeRun() || !updatableObjectFile.exists)
+				staticObjectFile.copyTo(updatableObjectFile, true);
+		
+			var loader:URLLoader = new URLLoader(new URLRequest("file://" + updatableObjectFile.nativePath));
+			loader.addEventListener(Event.COMPLETE, objectsXmlLoaded);			
+		}		
+		
+		private function objectsXmlLoaded(event:Event):void
+		{
+			trace("OBJECTS LOADED");
+			var loader:URLLoader = URLLoader(event.target);
+			objectXml = new XML(loader.data);
+			
+			loadSettings();
+			loadCategoriesAndObjects()
+			checkForNewObjectXml();
+		}
+		
+		private function loadCategoriesAndObjects():void
+		{
+			Config.OBJECTS_FILE_VERSION = objectXml.@version;
+			Config.OBJECTS_TOTAL = XMLList(objectXml..Object).length();
+			
+			var searchTagsLabels:Array = String(objectXml.@searchTags).split(",");
+			var searchTagsTotals:Array = String(objectXml.@searchTagsTotals).split(",");
+			var searchTagsCombined:Array = new Array();
+
+			for(var i:int=0; i<searchTagsLabels.length; i++)
+				searchTagsCombined.push([searchTagsLabels[i], searchTagsTotals[i]]);
+				
+			searchTags = searchTagsCombined;
+											
+			topLevelCategoriesXml = new XMLList(objectXml.children().@name);
+			selectedTopLevelCategory = topLevelCategoriesXml[0];
+			filterTopLevelCategory(selectedTopLevelCategory);	
+		}
+
+		//--------------------------------------------------------------------------
+		//  Filtering
+		//--------------------------------------------------------------------------		
+		public function filterTopLevelCategory(category:String):void
+		{
+			selectedTopLevelCategory = category;
+			listXml = new XMLListCollection(objectXml.Category.(@name == category)..Object);
+			//treeXml = new XMLListCollection(XMLList(objectXml.Category.(@name == category)));
+			treeXml = new XMLListCollection(XMLList(objectXml.Category));
+		}
+		
+		public function filterList(filterText:String, onlyTags:Boolean = false):XMLList // HS
+		{
+			filterText = filterText.toLowerCase();
+			var filterTextTerms:Array = filterText.split(" ");
+			var filteredList:XMLList = new XMLList();
+			
+			//for each(var objectItem:XML in objectXml.Category.(@name == selectedTopLevelCategory)..Object)
+			//for each(var objectItem:XML in objectXml..Object)
+			
+			var objectsToSearch:XML = objectXml.copy();
+			delete objectsToSearch.Category.(@name == "Featured").*;
+			
+			for each(var objectItem:XML in objectsToSearch..Object)
+			{
+				var name:String = objectItem.@name.toLowerCase();
+				var tags:String = objectItem.@tags.toLowerCase();
+				var author:String = objectItem.@author.toLowerCase();
+				
+				for each(var term:String in filterTextTerms)
+				{								
+					var found:Boolean = false;
+					if(onlyTags)
+					{
+						if(tags.indexOf(term) != -1)
+							found = true;
+					}
+					else
+					{
+						if(name.indexOf(term) != -1 || author.indexOf(term) != -1 || tags.indexOf(term) != -1)
+							found = true;
+					}
+					
+					if(found)
+					{
+						filteredList += objectItem;
+						break;					
+					}					
+				}
+			}
+			
+			listXml = new XMLListCollection(filteredList);
+			sort(previousSortType);
+			return filteredList; //HS
+		}
+
+		public function sort(sortType:String = ObjectListSortTypes.ALPHABETICAL):void
+		{
+			previousSortType = sortType;
+			var sortField:String = "@name";
+			var descending:Boolean = false;
+			var numeric:Boolean = false;
+			
+			switch(sortType)
+			{
+				case ObjectListSortTypes.ALPHABETICAL:
+					sortField = "@name";
+					break;
+				case ObjectListSortTypes.MOST_RECENT:
+					sortField = "@dateAdded";
+					descending = true;
+					break;
+				case ObjectListSortTypes.MOST_POPULAR:
+					sortField = "@viewCount";
+					descending = true;
+					numeric = true;
+					break;
+			}
+
+			var sort:Sort = new Sort();
+			sort.fields = [new SortField(sortField, true, descending, numeric)];
+			listXml.sort = sort;
+			listXml.refresh();
+		}
+			
+		//--------------------------------------------------------------------------
+		//  Settings / localization
+		//--------------------------------------------------------------------------	
+		private function loadSettings():void
+		{			
+			Config.PROGRAM_TITLE = objectXml.Settings.@title;
+			Config.ABOUT_MENU_LIST = objectXml.Settings.AboutMenu.Item;
+			Config.ABOUT_MENU_TITLE = objectXml.Settings.AboutMenu.@title;
+			
+			var appXml:XML = NativeApplication.nativeApplication.applicationDescriptor;
+			var ns:Namespace = appXml.namespace();
+			Config.APP_VERSION = appXml.ns::version;					
+		}		
+		
+		//--------------------------------------------------------------------------
+		//  Checking for new objects.xml and updating it 
+		//--------------------------------------------------------------------------		
+		private function checkForNewObjectXml():void
+		{
+			var loader:URLLoader = new URLLoader(new URLRequest(Config.OBJECTS_UPDATER_URL));
+			loader.addEventListener(Event.COMPLETE, objectsUpdaterXmlLoaded);
+			loader.addEventListener(IOErrorEvent.IO_ERROR, objectsUpdaterXmlLoadedError);
+		}
+		
+		private function objectsUpdaterXmlLoadedError(event:IOErrorEvent):void
+		{
+		}
+				
+		private function objectsUpdaterXmlLoaded(event:Event):void
+		{
+			var loader:URLLoader = URLLoader(event.target);
+			var objectsUpdaterXml:XML = new XML(loader.data);
+			
+			var currentVersion:String = objectXml.@version;
+			var onlineVersion:String = objectsUpdaterXml.version;
+			var onlineVersionDescription:String = objectsUpdaterXml.description;
+			
+			if(onlineVersion > currentVersion) {
+				downloadNewObjectXml(objectsUpdaterXml.url);
+				if(onlineVersionDescription.length > 0) {
+					// Only show notice if a description was provided, otherwise, silent install
+					var myPattern:RegExp = /\r\n/g;  
+					onlineVersionDescription = onlineVersionDescription.replace(myPattern,"\n");					
+					Alert.show(onlineVersionDescription, "Samples Database Updated to Version " + onlineVersion);
+				}
+			}
+		}
+		
+		private function downloadNewObjectXml(path:String):void
+		{
+			var loader:URLLoader = new URLLoader(new URLRequest(path));
+			loader.addEventListener(Event.COMPLETE, updatedObjectsXmlLoaded);
+			CursorManager.setBusyCursor();	
+		}
+		
+		public function updatedObjectsXmlLoaded(event:Event):void
+		{
+			var file:File = File.applicationStorageDirectory;
+			file = file.resolvePath(Config.OBJECTS_FILE);
+			if(file.exists)
+				file.deleteFile();
+
+			var loader:URLLoader = URLLoader(event.target);
+
+			objectXml = new XML(loader.data);	
+			loadSettings();	
+			loadCategoriesAndObjects();			
+
+			var fileStream:FileStream = new FileStream();
+			fileStream.open(file, FileMode.WRITE);
+			fileStream.writeUTFBytes(objectXml.toXMLString());
+			fileStream.close();	
+			CursorManager.removeBusyCursor();	
+
+		}			
+		//--------------------------------------------------------------------------
+		//--------------------------------------------------------------------------	
+		//------------------------------------------------------------------------
+		// Convert the XML objects into Component objects so they map to the remote 
+		// java object for easier processing by plug-in. HS
+		//------------------------------------------------------------------------
+		private function createComponentsFromXML(xmlList:XMLList):ArrayCollection 
+		{	
+			var objectsAsComponents:ArrayCollection = new ArrayCollection();
+			for each(var object:XML in xmlList)
+			{
+				trace("Component name " + object.attribute("name") + " id " + object.attribute("id"));	
+				var c:Component = new Component();
+				c.id = object.attribute("id");
+				c.name = object.attribute("name");	
+				c.author = object.attribute("author");
+				c.description = object.attribute("description");
+				objectsAsComponents.addItem(c);	
+			}
+			return objectsAsComponents;
+		}
+		//-----------------------------------------------------
+		// Find the matching components based on the search string
+		// passed from the Eclipse plug-in and add them to an Array
+		// Collection as component objects for return via Merapi. HS
+		//-----------------------------------------------------
+		public function getFilteredComponents(filter:String):ArrayCollection
+		{
+			// First setup the XML list based on the search string from the plugin
+			var resultList:XMLList = filterList(filter);			
+			var objectsAsComponents:ArrayCollection = createComponentsFromXML(resultList);
+			return objectsAsComponents;
+		}
+		//-----------------------------------------------------
+		// Fetch the list of featured components and convert them
+		// to component objects and add them to the array collection
+		// that will be returned to the eclipse plug-in. HS
+		//-----------------------------------------------------
+		public function getFeaturedComponents():ArrayCollection
+		{
+			// First setup the XML list based on the search string from the plugin
+			// Featured Components are the first child in the object XML...
+
+			var featXml:XML = objectXml.children()[0];
+			trace("Top level categories: " + featXml + objectXml.contains("Category"));
+			var featObjsList:XMLList = featXml.descendants("Object")
+			var objectsAsComponents:ArrayCollection = createComponentsFromXML(featObjsList);			
+			return objectsAsComponents;
+			
+		}
+		//-----------------------------------------------------
+		// Fetch the XML object for the id that was passed in
+		// from the Eclipse plug-in so we can navigate to that
+		// object for display. HS
+		//-----------------------------------------------------
+		public function getXMLForObjectId(matchId:String):XML {
+			var objects:XMLList = XMLList(objectXml..Object);
+			for each(var objectItem:XML in objects) {
+				var id:String = objectItem.@id.toLowerCase();
+				var name:String = objectItem.@name.toLowerCase();
+				var tags:String = objectItem.@tags.toLowerCase();
+				var author:String = objectItem.@author.toLowerCase();
+				if (id == matchId) {
+					trace("NAME: " + name + " id " + id);
+					return objectItem;
+				}
+			}
+			return null;
+		}
+
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/3dc107b9/TourDeFlex/TourDeFlex/src/classes/ObjectListSortTypes.as
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex/src/classes/ObjectListSortTypes.as b/TourDeFlex/TourDeFlex/src/classes/ObjectListSortTypes.as
new file mode 100644
index 0000000..6466fab
--- /dev/null
+++ b/TourDeFlex/TourDeFlex/src/classes/ObjectListSortTypes.as
@@ -0,0 +1,38 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package classes
+{
+	import mx.collections.ArrayCollection;
+	
+	public final class ObjectListSortTypes
+	{
+		
+		public static const ALPHABETICAL:String = "Alphabetical";
+		public static const MOST_RECENT:String = "Most Recent";
+		public static const MOST_POPULAR:String = "Most Popular";	
+		
+		[Bindable]
+		public static var ObjectListSortTypeArray:Array = [ALPHABETICAL, MOST_RECENT, MOST_POPULAR];
+		
+		public function ObjectListSortTypes()
+		{
+		}		
+
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/3dc107b9/TourDeFlex/TourDeFlex/src/classes/ObjectTreeDataDescriptor.as
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex/src/classes/ObjectTreeDataDescriptor.as b/TourDeFlex/TourDeFlex/src/classes/ObjectTreeDataDescriptor.as
new file mode 100644
index 0000000..7afbafd
--- /dev/null
+++ b/TourDeFlex/TourDeFlex/src/classes/ObjectTreeDataDescriptor.as
@@ -0,0 +1,191 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package classes
+{
+	import mx.collections.ArrayCollection;
+	import mx.collections.CursorBookmark;
+	import mx.collections.ICollectionView;
+	import mx.collections.IViewCursor;
+	import mx.collections.XMLListCollection;
+	import mx.controls.treeClasses.ITreeDataDescriptor;
+	import mx.events.CollectionEvent;
+	import mx.events.CollectionEventKind;
+	
+	public class ObjectTreeDataDescriptor implements ITreeDataDescriptor
+	{
+		public function ObjectTreeDataDescriptor()
+		{
+		}
+
+		public function getChildren(node:Object, model:Object=null):ICollectionView
+		{
+			try
+			{		
+				return new XMLListCollection(XMLList(node).children());
+			}
+			catch (e:Error)
+			{
+				trace("[Descriptor] exception checking for getChildren:" + e.toString());
+			}
+			return null;
+		}
+		
+		// The isBranch method simply returns true if the node is an
+		// Object with a children field.
+		// It does not support empty branches, but does support null children
+		// fields.
+		public function isBranch(node:Object, model:Object=null):Boolean
+		{
+			try
+			{
+				if(node is Object)
+				{
+					if(node.children != null && XML(node).name().toString() != "Object")
+						return true;
+				}
+			}
+			catch (e:Error)
+			{
+				trace("[Descriptor] exception checking for isBranch");
+			}
+			
+			return false;
+		}
+		
+		// The hasChildren method Returns true if the
+		// node actually has children. 
+		public function hasChildren(node:Object, model:Object=null):Boolean
+		{
+			if(node == null) 
+				return false;
+			
+			var children:ICollectionView = getChildren(node, model);
+			
+			try
+			{
+				if(children.length > 0)
+					return true;
+			}
+			catch(e:Error)
+			{
+				trace("hasChildren: " + e.toString());
+			}
+			
+			return false;
+		}
+		
+		// The getData method simply returns the node as an Object.
+		public function getData(node:Object, model:Object=null):Object
+		{
+			try
+			{
+				return node;
+			}
+			catch (e:Error)
+			{
+				trace("getData: " + e.toString());
+			}
+			
+			return null;
+		}
+		
+		// The addChildAt method does the following:
+		// If the parent parameter is null or undefined, inserts
+		// the child parameter as the first child of the model parameter.
+		// If the parent parameter is an Object and has a children field,
+		// adds the child parameter to it at the index parameter location.
+		// It does not add a child to a terminal node if it does not have
+		// a children field.
+		public function addChildAt(parent:Object, child:Object, index:int, model:Object=null):Boolean
+		{
+			var event:CollectionEvent = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+			event.kind = CollectionEventKind.ADD;
+			event.items = [child];
+			event.location = index;
+			
+			if (!parent)
+			{
+				var iterator:IViewCursor = model.createCursor();
+				iterator.seek(CursorBookmark.FIRST, index);
+				iterator.insert(child);
+			}
+			else if (parent is Object)
+			{
+				if (parent.children != null)
+				{
+					if(parent.children is ArrayCollection)
+					{
+						parent.children.addItemAt(child, index);
+						if (model)
+						{
+							model.dispatchEvent(event);
+							model.itemUpdated(parent);
+						}
+						return true;
+					}
+					else
+					{
+						parent.children.splice(index, 0, child);
+						if(model)
+							model.dispatchEvent(event);
+						return true;
+					}
+				}
+			}
+			return false;
+		}
+		
+		// The removeChildAt method does the following:
+		// If the parent parameter is null or undefined,
+		// removes the child at the specified index
+		// in the model.
+		// If the parent parameter is an Object and has a children field,
+		// removes the child at the index parameter location in the parent.
+		public function removeChildAt(parent:Object, child:Object, index:int, model:Object=null):Boolean
+		{
+			var event:CollectionEvent = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+			event.kind = CollectionEventKind.REMOVE;
+			event.items = [child];
+			event.location = index;
+		
+			//handle top level where there is no parent
+			if (!parent)
+			{
+				var iterator:IViewCursor = model.createCursor();
+				iterator.seek(CursorBookmark.FIRST, index);
+				iterator.remove();
+				if (model)
+						model.dispatchEvent(event);
+				return true;
+			}
+			else if (parent is Object)
+			{
+				if (parent.children != undefined)
+				{
+					parent.children.splice(index, 1);
+					if(model) 
+						model.dispatchEvent(event);
+					return true;
+				}
+			}
+			return false;
+		}
+
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/3dc107b9/TourDeFlex/TourDeFlex/src/classes/ObjectTreeItemRenderer.as
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex/src/classes/ObjectTreeItemRenderer.as b/TourDeFlex/TourDeFlex/src/classes/ObjectTreeItemRenderer.as
new file mode 100644
index 0000000..e58fc5c
--- /dev/null
+++ b/TourDeFlex/TourDeFlex/src/classes/ObjectTreeItemRenderer.as
@@ -0,0 +1,94 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package classes
+{
+	import mx.controls.Image;
+	import mx.controls.treeClasses.TreeItemRenderer;
+	import mx.controls.treeClasses.TreeListData;
+
+	public class ObjectTreeItemRenderer extends TreeItemRenderer
+	{
+		protected var iconImage:Image;
+		private var imageWidth:Number	= 18;
+		private var imageHeight:Number	= 18;
+		private var imageToLabelMargin:Number = 2;
+		
+		public function ObjectTreeItemRenderer()
+		{
+			super();
+		}
+		
+		override protected function createChildren():void
+		{	
+			iconImage = new Image();	
+			iconImage.width = imageWidth;
+			iconImage.height = imageHeight;
+			addChild(iconImage);	
+	
+			super.createChildren();
+		} 
+		
+		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
+		{
+			super.updateDisplayList(unscaledWidth, unscaledHeight);
+			if(super.data)
+			{
+				if(!TreeListData(super.listData).hasChildren)
+				{
+					iconImage.x = super.label.x - imageWidth - imageToLabelMargin;
+					
+					var tmp:XMLList = new XMLList(TreeListData(super.listData).item);					
+					var iconPath:String = tmp.@iconPath.toString();
+					if(tmp.@localIconPath.toString().length > 0)
+						iconPath = tmp.@localIconPath;
+						
+					if(iconPath.length > 0)
+					{
+						if(hasFullPath(iconPath)) {
+							if (Config.IS_ONLINE) {
+								iconImage.source = iconPath;
+							} else {
+								iconImage.source = Config.TREE_NO_ICON;
+							}
+						}
+						else
+							iconImage.source = Config.LOCAL_OBJECTS_ROOT_PATH + iconPath;
+					}
+					else
+					{
+						iconImage.source = Config.TREE_NO_ICON;
+					}										
+				}
+				else
+				{
+					iconImage.source = null;
+				}
+			}
+		}
+		
+		private function hasFullPath(path:String):Boolean
+		{
+			if(path.indexOf("//") >= 0 || path.indexOf(":") >= 0)
+				return true;
+			else
+				return false;
+		}
+		
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/3dc107b9/TourDeFlex/TourDeFlex/src/components/AboutWindow.mxml
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex/src/components/AboutWindow.mxml b/TourDeFlex/TourDeFlex/src/components/AboutWindow.mxml
new file mode 100644
index 0000000..da94159
--- /dev/null
+++ b/TourDeFlex/TourDeFlex/src/components/AboutWindow.mxml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+-->
+<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="500" height="430" horizontalScrollPolicy="off" verticalScrollPolicy="off" click="closeAbout()">
+	
+	<mx:Script>
+	<![CDATA[
+		import mx.managers.PopUpManager;
+		
+		public var isOpen:Boolean = false;
+		
+		public function set url(value:String):void
+		{
+			html_view.htmlLoader.navigateInSystemBrowser = true;
+			html_view.location = value;			
+		}
+		
+		public function closeAbout():void {
+			isOpen = false;
+			parentApplication.setFocus(); 
+			PopUpManager.removePopUp(this)
+		}
+		
+	]]>
+	</mx:Script>
+
+	<mx:Parallel id="aboutEffect">
+		<mx:Fade alphaFrom="0" alphaTo="1" duration="300"/>
+		<mx:Blur blurXFrom="300" blurXTo="0" duration="700"/>
+	</mx:Parallel>
+
+	<mx:Parallel id="shadowEffect">
+		<mx:Fade duration="1000"/>
+		<mx:Blur blurXFrom="0" blurYFrom="0" blurXTo="20" blurYTo="20" duration="500"/>
+		<mx:Fade duration="1000"/>
+	</mx:Parallel>
+
+	<mx:Canvas x="15" y="15" backgroundColor="black" backgroundAlpha="0.5" width="434" height="368" addedEffect="shadowEffect"/>
+	<mx:HTML x="0" y="0" id="html_view" width="439" height="368" addedEffect="aboutEffect" verticalScrollPolicy="off" horizontalScrollPolicy="off" />
+	
+</mx:Canvas>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/3dc107b9/TourDeFlex/TourDeFlex/src/components/ApplicationFooter.mxml
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex/src/components/ApplicationFooter.mxml b/TourDeFlex/TourDeFlex/src/components/ApplicationFooter.mxml
new file mode 100644
index 0000000..430629d
--- /dev/null
+++ b/TourDeFlex/TourDeFlex/src/components/ApplicationFooter.mxml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+-->
+<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()" width="100%" height="30" styleName="applicationFooter">
+
+	<mx:Script >
+	<![CDATA[
+		import mx.managers.PopUpManager;
+		
+		private var popup:AboutWindow;
+		
+		private function init():void
+		{
+			popup = new AboutWindow();
+		}
+		
+		private function showAbout():void
+		{
+			if(!popup.isOpen)
+			{				
+				PopUpManager.addPopUp(popup, DisplayObject(this.parentApplication), false);
+				popup.url = "data/about.html";
+				popup.isOpen = true;
+				PopUpManager.centerPopUp(popup);
+				popup.move(popup.x + 70, popup.y + 50);
+			}
+			else
+			{			
+				popup.isOpen = false;	
+				PopUpManager.removePopUp(popup);
+			}
+		}
+		
+	]]>
+	</mx:Script>
+	<mx:Button x="4" y="1" id="aboutBtn" styleName="aboutButton" click="showAbout();" />
+	<mx:HBox x="70" width="100%" height="100%" verticalAlign="middle">
+		<mx:Label text="©2010 Adobe Inc, All Rights Reserved" width="25%" textAlign="center" />
+		<mx:Label id="label_version" text="Version: {Config.APP_VERSION}" width="25%" textAlign="center" />
+		<mx:Label id="label_objectsDataVersion" text="List Version: {Config.OBJECTS_FILE_VERSION}" width="25%" textAlign="center" />
+		<mx:Label id="label_objectsTotal" text="Samples: {Config.OBJECTS_TOTAL}" width="25%" textAlign="center" />		
+	</mx:HBox>	
+	
+	<mx:Image bottom="5" right="4" source="@Embed('/images/button_clear.png')" mouseDown="stage.nativeWindow.startResize()" buttonMode="true" mouseEnabled="true" useHandCursor="true" />
+	
+</mx:Canvas>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/3dc107b9/TourDeFlex/TourDeFlex/src/components/ApplicationHeader.mxml
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex/src/components/ApplicationHeader.mxml b/TourDeFlex/TourDeFlex/src/components/ApplicationHeader.mxml
new file mode 100644
index 0000000..65713b0
--- /dev/null
+++ b/TourDeFlex/TourDeFlex/src/components/ApplicationHeader.mxml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+-->
+<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="42"
+	 verticalScrollPolicy="off" horizontalScrollPolicy="off" backgroundAlpha="0">
+	
+	<mx:Script>
+	<![CDATA[
+		import mx.controls.Alert;
+		import mx.managers.PopUpManager;
+		import mx.events.ListEvent;
+		
+		[Bindable]
+		private var resourceTitle:String = " ";
+		
+		/*
+		private function comboBox_about_change(event:ListEvent):void
+		{	
+			if(comboBox_about.selectedItem.@data.toString().toLowerCase().indexOf("http") == 0)
+			{
+				navigateToURL(new URLRequest(comboBox_about.selectedItem.@data));
+			}
+			else if(comboBox_about.selectedItem.@data == "SplashWindow")
+			{
+				var splashWindow:SplashWindow = new SplashWindow();
+				PopUpManager.addPopUp(splashWindow, DisplayObject(this.parentApplication), false);
+				PopUpManager.centerPopUp(splashWindow);
+			}
+			else
+			{
+				var popup:AboutWindow = new AboutWindow();
+				PopUpManager.addPopUp(popup, DisplayObject(this.parentApplication), false);
+				popup.url = comboBox_about.selectedItem.@data;
+				PopUpManager.centerPopUp(popup);
+				popup.move(popup.x + 70, popup.y + 50);	 // move it 50 pixels right - GAW						
+			}
+			comboBox_about.selectedIndex = -1; // Reset menu
+		}
+		*/
+		
+		private function button_quickStart_click(event:MouseEvent):void
+		{				
+			TourDeFlex(this.parentApplication).showQuickStart();
+		}
+		
+	]]>
+	</mx:Script>
+	
+	<mx:HBox styleName="applicationHeader" width="100%" height="100%"  mouseDown="stage.nativeWindow.startMove()" />
+	
+	<!--<mx:VBox right="37" y="2" height="100%" verticalAlign="middle" horizontalAlign="right">-->
+		<mx:HBox right="6" y="10" paddingTop="2" width="214" horizontalGap="2" horizontalScrollPolicy="off">
+			<mx:Button styleName="aboutComboBox" width="103" height="14" click="button_quickStart_click(event)" />
+			<!--<mx:ComboBox id="comboBox_about" prompt="{resourceTitle}" width="103" height="14" change="comboBox_about_change(event)" rowCount="20" styleName="aboutComboBox" dataProvider="{Config.ABOUT_MENU_LIST}" labelField="@label" />-->	
+			<!--prompt="{Config.ABOUT_MENU_TITLE}" -->
+			<mx:Spacer width="30" />
+			<mx:Button width="20" styleName="applicationMinimizeButton" click="parentApplication.minimize()" tabEnabled="false" toolTip="Minimize" buttonMode="true" mouseEnabled="true" useHandCursor="true" />
+			<mx:Button width="20" styleName="applicationMaximizeButton" click="if(stage.displayState == StageDisplayState.FULL_SCREEN_INTERACTIVE) stage.displayState = StageDisplayState.NORMAL; else stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE" tabEnabled="false" toolTip="Full Screen" buttonMode="true" mouseEnabled="true" useHandCursor="true" />
+			<mx:Button width="20" styleName="applicationCloseButton" 
+				click="NativeApplication.nativeApplication.dispatchEvent(new Event(Event.EXITING,true,true));" 
+				tabEnabled="false" toolTip="Close" buttonMode="true" mouseEnabled="true" useHandCursor="true" />
+				
+		</mx:HBox>
+	<!--</mx:VBox>-->	
+</mx:Canvas>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/3dc107b9/TourDeFlex/TourDeFlex/src/components/CommentsWindow.mxml
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex/src/components/CommentsWindow.mxml b/TourDeFlex/TourDeFlex/src/components/CommentsWindow.mxml
new file mode 100644
index 0000000..54e403b
--- /dev/null
+++ b/TourDeFlex/TourDeFlex/src/components/CommentsWindow.mxml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+-->
+<WipeWindow xmlns="components.*" xmlns:mx="http://www.adobe.com/2006/mxml" horizontalAlign="right">
+
+	<mx:Script>
+	<![CDATA[
+		
+		private var commentsInitiallyLoaded:Boolean = false;
+		
+		public function loadComments(objectId:int, isOnline:Boolean):void
+		{
+			if(isOnline)
+				this.html_comments.location = Config.COMMENTS_URL + objectId;
+			else
+				this.html_comments.location = Config.OFFLINE_URL;
+		}
+		
+		private function html_comments_loaded(event:Event):void
+		{			
+			if(commentsInitiallyLoaded)
+				this.parentApplication.HTTP_GetCommentsTotal.send();
+			
+			commentsInitiallyLoaded = true;
+		}
+		
+	]]>
+	</mx:Script>
+	
+	<mx:Button click="{this.visible = false}" styleName="closeButton"/>
+	
+	<mx:HTML id="html_comments" width="100%" height="100%" complete="html_comments_loaded(event)" />
+	
+</WipeWindow>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/3dc107b9/TourDeFlex/TourDeFlex/src/components/DocumentTabs.mxml
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex/src/components/DocumentTabs.mxml b/TourDeFlex/TourDeFlex/src/components/DocumentTabs.mxml
new file mode 100644
index 0000000..01fe4d7
--- /dev/null
+++ b/TourDeFlex/TourDeFlex/src/components/DocumentTabs.mxml
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+-->
+<mx:TabNavigator xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="components.*"
+					   width="100%" height="100%" styleName="documentTabs" selectedTabTextStyleName="documentTabSelected">
+
+	<mx:Script>
+	<![CDATA[
+		import classes.Document;
+		import mx.controls.HTML;
+		import mx.containers.VBox;
+		
+		public var needHtmlHack:Boolean = false; // This is a total hack to work around TWO bugs in Flex.  Ask Greg Wilson for details
+				
+		public function addTabs(documents:Array, localRootPath:String):void
+		{
+			this.selectedIndex = 0;
+			this.validateNow();
+			this.removeAllChildren();
+						
+			for each(var document:Document in documents)
+				this.addTab(document.name, document.path, document.openLinksExternal, localRootPath);
+		}
+		
+		// There is a bug in the Flex 3.2 html control where the default font is set too large.  This method puts it back to the desired default of 11px.
+		public function changeDefaultFont(e:Event):void {
+			var frames:Object = e.target.htmlLoader.window.document.getElementsByTagName("frame");
+			if (frames.length == 0)
+			{
+				// document does not have frames
+				if(e.target.htmlLoader.window.document.getElementsByTagName("body")[0])
+					e.target.htmlLoader.window.document.getElementsByTagName("body")[0].style.fontSize="11px";
+			}
+			else
+			{
+				// document has frames... change style for document in each frame
+				for (var i:int=0;i<frames.length;i++)
+				{
+					if(frames[i].contentDocument.getElementsByTagName("body")[0])
+						frames[i].contentDocument.getElementsByTagName("body")[0].style.fontSize="11px";
+				}
+			}
+			e.target.visible = true;
+		}
+	
+		public function removeCleanup(e:Event):void {
+			if (this.needHtmlHack) {
+				//trace("CLEANUP");
+				e.target.htmlText = ""; // Hack - GAW - forces any loaded SWFs to stop
+			}
+		}
+
+		
+		public function addTab(name:String, path:String, openLinksExternal:String, localRootPath:String):void
+		{
+			var tab:VBox = new VBox();
+			tab.percentWidth = 100;
+			tab.percentHeight = 100;
+			if(name.length == 0)
+				tab.label = getFileName(path);
+			else
+				tab.label = name;
+			this.addChild(tab);
+			
+			var html_illustration:HTML = new HTML();
+			html_illustration.percentWidth = 100;
+			html_illustration.percentHeight = 100;
+			html_illustration.visible = false;   // Set to true after changeDefaultFont
+			html_illustration.addEventListener(Event.COMPLETE,changeDefaultFont);
+			html_illustration.addEventListener(Event.REMOVED_FROM_STAGE, removeCleanup);
+			tab.addChild(html_illustration);	
+			
+			if (openLinksExternal.toLowerCase() == "true") 
+			{
+				html_illustration.htmlLoader.navigateInSystemBrowser = true; // Open links in default browser
+			}
+			
+			if(path.toLowerCase().indexOf("http") == 0)
+			{
+				if(Config.IS_ONLINE)
+					html_illustration.location = path;
+				else
+					html_illustration.location = Config.OFFLINE_URL;
+			}
+			else
+			{
+				html_illustration.location = localRootPath + path;
+			}
+		}
+		
+		private function getFileName(path:String):String
+		{
+			var fileName:String = "";
+			var slashPos:int = path.lastIndexOf("/");
+			var backslashPos:int = path.lastIndexOf("\\");
+			
+			if(slashPos > 0)
+				fileName = path.substr(slashPos+1); 
+			else if(backslashPos > 0)	
+				fileName = path.substr(backslashPos+1);	
+			else
+				fileName = "Document";
+				
+			return fileName;
+		}
+		
+	]]>
+	</mx:Script>
+
+</mx:TabNavigator>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/3dc107b9/TourDeFlex/TourDeFlex/src/components/DownloadWindow.mxml
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex/src/components/DownloadWindow.mxml b/TourDeFlex/TourDeFlex/src/components/DownloadWindow.mxml
new file mode 100644
index 0000000..c118aeb
--- /dev/null
+++ b/TourDeFlex/TourDeFlex/src/components/DownloadWindow.mxml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+-->
+<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" horizontalAlign="center" verticalAlign="middle" styleName="downloadWindow" width="300" height="150" creationComplete="init()">
+	<mx:Script>
+	<![CDATA[
+		import mx.controls.Alert;
+		import mx.managers.PopUpManager;
+		
+		private var fileReference:FileReference;
+		private var localFileToSave:File;
+		private var fileToSave:File;
+				
+		private function init():void
+		{
+			fileReference = new FileReference();
+		}
+		
+		public function download(path:String, localRootPath:String):void
+		{
+			if(path.toLowerCase().indexOf("http") == 0)
+				downloadHttp(path);
+			else
+				downloadLocal(localRootPath + path);			
+		}
+		
+		private function downloadLocal(path:String):void
+		{		
+			localFileToSave = File.applicationDirectory.resolvePath(path);
+			
+			fileToSave = new File(File.documentsDirectory.nativePath + File.separator + localFileToSave.name);
+			fileToSave.addEventListener(Event.SELECT, downloadLocal_directorySelect);
+			fileToSave.addEventListener(Event.CANCEL, downloadLocal_directorySelectCancel);
+			fileToSave.browseForSave("Save As");			
+		}
+		
+		private function downloadLocal_directorySelect(event:Event):void 
+		{			
+			localFileToSave.addEventListener(ProgressEvent.PROGRESS, download_progressHandler);
+			localFileToSave.addEventListener(Event.COMPLETE, download_completeHandler);
+			localFileToSave.copyToAsync(fileToSave, true);
+			progressBar_download.setProgress(100,100);
+		}	
+		
+		private function downloadLocal_directorySelectCancel(event:Event):void 
+		{
+			PopUpManager.removePopUp(this);
+		}		
+
+		private function downloadHttp(path:String):void
+		{
+			var request:URLRequest = new URLRequest(path);
+			fileReference = new FileReference();
+			fileReference.addEventListener(Event.OPEN, download_openHandler);
+			fileReference.addEventListener(ProgressEvent.PROGRESS, download_progressHandler);
+			fileReference.addEventListener(Event.COMPLETE, download_completeHandler);
+			
+			try
+			{
+				fileReference.download(request);
+			}
+			catch (error:Error)
+			{
+				Alert.show(error.message, "Download Error");
+			}
+		}
+		
+		private function download_openHandler(event:Event):void
+    {
+			progressBar_download.label = "DOWNLOADING %3%%";
+			button_cancel.visible = true;
+			button_close.visible = false;
+    }
+		
+ 		private function download_progressHandler(event:ProgressEvent):void
+		{
+			progressBar_download.setProgress(event.bytesLoaded, event.bytesTotal);
+		}	
+		
+ 		private function download_cancel(event:MouseEvent):void
+		{
+			fileReference.cancel();
+			progressBar_download.label = "CANCELLED";
+			button_close.visible = true;
+			button_cancel.visible = false;
+			
+			PopUpManager.removePopUp(this);
+		}			
+		
+		private function download_completeHandler(event:Event):void
+		{
+			progressBar_download.label = "DOWNLOAD COMPLETE";
+			button_close.visible = true;
+			button_cancel.visible = false;
+		}
+		
+	]]>
+	</mx:Script>	
+	
+	<mx:ProgressBar id="progressBar_download" width="90%" mode="manual" label="DOWNLOADING..." />	
+	
+	<mx:Canvas>
+		<mx:Button id="button_cancel" label="Cancel" visible="false" click="download_cancel(event)" horizontalCenter="0" />		
+		<mx:Button id="button_close" label="Close" click="{PopUpManager.removePopUp(this)}" horizontalCenter="0"/>
+	</mx:Canvas>
+	
+</mx:TitleWindow>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/3dc107b9/TourDeFlex/TourDeFlex/src/components/IllustrationTab.mxml
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex/src/components/IllustrationTab.mxml b/TourDeFlex/TourDeFlex/src/components/IllustrationTab.mxml
new file mode 100644
index 0000000..df4bcbb
--- /dev/null
+++ b/TourDeFlex/TourDeFlex/src/components/IllustrationTab.mxml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+-->
+<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" remove="unloadIllustration();">
+	
+	<mx:Script>
+	<![CDATA[
+		import mx.controls.Alert;
+		import mx.core.Application;
+		import mx.core.FlexGlobals;
+		import mx.modules.ModuleLoader;
+		
+		public var downloadPath:String = "";
+		public var illustrationURL:String = "";
+		public var autoExpand:Boolean = false;
+
+		public function setLocation(path:String, isModule:String):void
+		{			
+			//mx.core.Application.application.button_expand.enabled = true;
+			FlexGlobals.topLevelApplication.button_expand.enabled = true;
+			
+			if(isModule.toLowerCase() == "true")
+			{
+				this.removeChild(html_illustration);
+				module_swfs.url = path;
+				illustrationURL = "";
+				FlexGlobals.topLevelApplication.button_browser.enabled = false;
+			}
+			else
+			{				
+				this.removeChild(module_swfs);
+				html_illustration.location = path;
+				illustrationURL = path;
+				FlexGlobals.topLevelApplication.button_browser.enabled = true;
+
+			}			
+		}
+		
+		public function unloadIllustration():void {
+			if (this.contains(html_illustration)) 
+			{
+				html_illustration.htmlText = ""; // hack - GAW
+ 				this.removeChild(html_illustration); // hack - GAW				
+			} 
+			else
+			{	
+				module_swfs.unloadModule();
+ 			}
+		}
+		
+	]]>
+	</mx:Script>
+	
+	<mx:Parallel id="arrowShow">
+		<mx:Fade alphaFrom="0.5" alphaTo="1.0" duration="500"/>
+	</mx:Parallel>
+
+	<mx:Parallel id="arrowDim">	
+		<mx:Fade alphaFrom="1.0" alphaTo="0.5" duration="500"/>
+	</mx:Parallel>
+		
+	<mx:HTML id="html_illustration" width="100%" height="100%" horizontalScrollPolicy="off" verticalScrollPolicy="off" />
+	<mx:ModuleLoader id="module_swfs" height="100%" width="100%" backgroundColor="#323232" horizontalAlign="center" verticalAlign="middle" />
+
+</mx:Canvas>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/3dc107b9/TourDeFlex/TourDeFlex/src/components/IllustrationTabs.mxml
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex/src/components/IllustrationTabs.mxml b/TourDeFlex/TourDeFlex/src/components/IllustrationTabs.mxml
new file mode 100644
index 0000000..26d55c5
--- /dev/null
+++ b/TourDeFlex/TourDeFlex/src/components/IllustrationTabs.mxml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+-->
+<local:TDFTabNavigator xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="components.*" width="100%" height="100%"  
+	creationComplete="init()" styleName="illustrationTabs"  selectedTabTextStyleName="illustrationTabSelected">
+
+	<mx:Script>
+	<![CDATA[
+		import mx.controls.Image;
+		import mx.collections.ArrayCollection;
+		import mx.controls.HTML;
+		import mx.containers.VBox;
+		
+		public var associatedDocumentsCollection:ArrayCollection;
+		
+		private function init():void
+		{
+			var t:TDFTabNavigator = new TDFTabNavigator();
+			associatedDocumentsCollection = new ArrayCollection();
+		}
+		
+		public function addTab(name:String, path:String, localRootPath:String, isModule:String, downloadPath:String, autoExpand:String, openLinksExternal:String, scrollBars:String, associatedDocuments:Array):void
+		{
+			this.associatedDocumentsCollection.addItem(associatedDocuments);
+						
+			var tab:IllustrationTab = new IllustrationTab();
+			tab.downloadPath = downloadPath;	
+			tab.autoExpand = (autoExpand.toLowerCase() == "true")? true:false;
+			
+			if(name.length == 0)
+				tab.label = "Sample " + (this.getChildren().length + 1);
+			else
+				tab.label = name;
+				
+			this.addChild(tab);
+
+			if(scrollBars.toLowerCase() == "true") {
+				tab.html_illustration.verticalScrollPolicy = "auto";
+				tab.html_illustration.horizontalScrollPolicy = "auto";
+			}
+			
+			if(openLinksExternal.toLowerCase() == "true") 
+				tab.html_illustration.htmlLoader.navigateInSystemBrowser = true;
+
+			if(path.toLowerCase().indexOf("http") == 0)
+				tab.setLocation(path, isModule);
+			else
+				tab.setLocation(localRootPath + path, isModule);
+		}
+		
+		public function removeAllIllustrations():void
+		{
+			//reset selected tab due to tab selection issue - HS - took out, use TDFTabNavigator class now instead.
+			//this.selectedIndex = 0;
+			//this.validateNow();
+			
+			this.removeAllChildren();
+			this.associatedDocumentsCollection.removeAll();
+			
+		}
+		
+		public function hideSwf():void
+		{
+			this.selectedChild.visible = false;
+		}
+		
+	]]>
+	</mx:Script>
+
+</local:TDFTabNavigator>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/3dc107b9/TourDeFlex/TourDeFlex/src/components/ObjectList.mxml
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex/src/components/ObjectList.mxml b/TourDeFlex/TourDeFlex/src/components/ObjectList.mxml
new file mode 100644
index 0000000..d9155ed
--- /dev/null
+++ b/TourDeFlex/TourDeFlex/src/components/ObjectList.mxml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+-->
+<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="98%" height="98%">
+	
+	<mx:Script>
+	<![CDATA[
+		import classes.ObjectListSortTypes;
+		import classes.ObjectTreeItemRenderer;
+		import classes.ObjectTreeDataDescriptor;
+		import mx.events.FlexEvent;
+		import mx.collections.XMLListCollection;
+		import mx.events.ListEvent;
+
+		[Bindable] public var treeDataProvider:Object;
+		[Bindable] public var listDataProvider:Object;
+		[Bindable] public var selectedId:int = -1;
+		[Bindable] public var selectedObject:XML;	
+		[Bindable] public var sortType:String = "";		
+		public static const SORT_CHANGE:String = "sortChange";
+
+		private function list_objects_change(event:ListEvent):void
+		{
+			dispatchEvent(event);
+		}
+
+		private function comboBox_sort_change(event:ListEvent):void
+		{
+			sortType = comboBox_sort.selectedLabel;
+			var sortEvent:ListEvent = new ListEvent(SORT_CHANGE, event.bubbles, event.cancelable, event.columnIndex, event.rowIndex, event.reason, event.itemRenderer);
+			dispatchEvent(sortEvent);
+		}
+				
+		private function tree_dataChange(event:FlexEvent):void
+		{
+			if(treeDataProvider && treeDataProvider[0].@autoExpand == true)
+				tree_objects.expandChildrenOf(treeDataProvider[0], true);
+		}
+		
+		public function showTreeView(show:Boolean):void
+		{
+			tree_objects.visible = show;
+			box_list_objects.visible = !show;
+		}
+		
+		public function setDescription(description:String, dateAdded:String, author:String):void
+		{
+			text_description.htmlText = description + "<br><b>Author:</b> " + author + "<br><b>Date Added:</b> " + dateAdded; 
+		}
+						
+	]]>
+	</mx:Script>
+	
+	<mx:Metadata>
+		[Event(name="change", type="mx.events.ListEvent")]
+		[Event(name="sortChange", type="mx.events.ListEvent")]		
+	</mx:Metadata>
+
+	<mx:Canvas width="100%" height="100%">
+		
+		<mx:VBox id="box_list_objects" width="100%" height="100%">			
+			<mx:ComboBox id="comboBox_sort" width="100%" change="comboBox_sort_change(event)" dataProvider="{ObjectListSortTypes.ObjectListSortTypeArray}" /> 
+			<mx:List id="list_objects" fontSize="11" fontAntiAliasType="advanced" labelField="@name" itemRenderer="components.ObjectListItemRenderer" change="list_objects_change(event)" dataProvider="{listDataProvider}" width="100%" height="100%" />
+		</mx:VBox>
+		
+		<mx:Tree id="tree_objects"  fontSize="11" fontAntiAliasType="advanced" labelField="@name" showRoot="true" defaultLeafIcon="{null}" valueCommit="tree_dataChange(event)" itemRenderer="classes.ObjectTreeItemRenderer" change="list_objects_change(event)" dataProvider="{treeDataProvider}" dataDescriptor="{new ObjectTreeDataDescriptor()}" height="100%" width="100%" openDuration="0" />
+	
+	</mx:Canvas>
+
+	<mx:Text id="text_description" width="100%" />
+	
+</mx:VBox>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/3dc107b9/TourDeFlex/TourDeFlex/src/components/ObjectListItemRenderer.mxml
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex/src/components/ObjectListItemRenderer.mxml b/TourDeFlex/TourDeFlex/src/components/ObjectListItemRenderer.mxml
new file mode 100644
index 0000000..39bc381
--- /dev/null
+++ b/TourDeFlex/TourDeFlex/src/components/ObjectListItemRenderer.mxml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+-->
+<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" implements="mx.controls.listClasses.IDropInListItemRenderer" horizontalScrollPolicy="off">
+	
+	<mx:Script>
+	<![CDATA[
+		import mx.controls.listClasses.BaseListData;
+
+		private var _listData:BaseListData;		
+		
+		public function get listData():BaseListData
+		{
+			return _listData;
+		}
+		
+		public function set listData(value:BaseListData):void
+		{
+			_listData = value;
+		}	
+		
+		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
+		{
+			super.updateDisplayList(unscaledWidth, unscaledHeight);
+			
+			if(data)
+			{
+				label_name.text = data.@name;
+				var iconPath:String = data.@iconPath;
+				if(data.@localIconPath.toString().length > 0)
+					iconPath = data.@localIconPath;
+					
+				//Config.IS_ONLINE
+				if(iconPath.length > 0)
+				{
+					if(hasFullPath(data.@iconPath) && data.@localIconPath.toString().length == 0)
+					{
+						if(Config.IS_ONLINE) {
+							image_icon.source = iconPath;
+						} else {
+							image_icon.source = Config.TREE_NO_ICON;
+						}
+					} 
+					else
+					{
+						image_icon.source = Config.LOCAL_OBJECTS_ROOT_PATH + iconPath;
+					}
+				}
+				else
+				{
+					image_icon.source = Config.TREE_NO_ICON;
+				}	
+			}		
+		}
+		
+		private function hasFullPath(path:String):Boolean
+		{
+			if(path.indexOf("//") >= 0 || path.indexOf(":") >= 0)
+				return true;
+			else
+				return false;
+		}
+			
+	]]>
+	</mx:Script>
+	
+	<mx:Image id="image_icon" width="18" height="18" />
+	<mx:Label id="label_name" x="20" />
+	
+</mx:Canvas>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/3dc107b9/TourDeFlex/TourDeFlex/src/components/PluginDownloadWindow.mxml
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex/src/components/PluginDownloadWindow.mxml b/TourDeFlex/TourDeFlex/src/components/PluginDownloadWindow.mxml
new file mode 100644
index 0000000..82b5297
--- /dev/null
+++ b/TourDeFlex/TourDeFlex/src/components/PluginDownloadWindow.mxml
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+-->
+<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" horizontalAlign="center" verticalAlign="middle" styleName="downloadWindow" width="300" height="150" creationComplete="init()">
+	<mx:Script>
+	<![CDATA[
+		import mx.controls.Alert;
+		import mx.managers.PopUpManager;
+		
+		private var fileReference:FileReference;
+		private var localFileToSave:File;
+		private var fileToSave:File;
+				
+		private function init():void
+		{
+			fileReference = new FileReference();
+		}
+		
+		public function download(samplePath:String, pluginPath:String, localRootPath:String):void
+		{
+			if(samplePath.toLowerCase().indexOf("http") == 0)
+				downloadHttp(samplePath);
+			else
+				downloadLocal(localRootPath + samplePath, pluginPath);			
+		}
+		
+		private function downloadLocal(samplePath:String, path:String):void
+		{		
+			var sampleFile:File = File.applicationDirectory.resolvePath(samplePath);
+			localFileToSave = File.documentsDirectory.resolvePath(path);
+			
+			fileToSave = new File(localFileToSave.nativePath + File.separator +  sampleFile.name);
+			//fileToSave.resolvePath(path);
+			fileToSave.nativePath = path;
+			fileToSave.addEventListener(Event.SELECT, downloadLocal_directorySelect);		
+			fileToSave.addEventListener(Event.CANCEL, downloadLocal_directorySelectCancel);
+			fileToSave.browseForSave("Save to project:");
+			
+		}
+		
+		private function downloadLocal_directorySelect(event:Event):void 
+		{			
+			localFileToSave.addEventListener(ProgressEvent.PROGRESS, download_progressHandler);
+			localFileToSave.addEventListener(Event.COMPLETE, download_completeHandler);
+			localFileToSave.copyToAsync(fileToSave, true);
+			progressBar_download.setProgress(100,100);
+		}		
+		private function downloadLocal_directorySelectCancel(event:Event):void 
+		{
+			PopUpManager.removePopUp(this);
+		}	
+		private function downloadHttp(path:String):void
+		{
+			var request:URLRequest = new URLRequest(path);
+			fileReference = new FileReference();
+			fileReference.addEventListener(Event.OPEN, download_openHandler);
+			fileReference.addEventListener(ProgressEvent.PROGRESS, download_progressHandler);
+			fileReference.addEventListener(Event.COMPLETE, download_completeHandler);
+			
+			try
+			{
+				fileReference.download(request);
+			}
+			catch (error:Error)
+			{
+				Alert.show(error.message, "Download Error");
+			}
+		}
+		
+		private function download_openHandler(event:Event):void
+    {
+			progressBar_download.label = "DOWNLOADING %3%%";
+			button_cancel.visible = true;
+			button_close.visible = false;
+    }
+		
+ 		private function download_progressHandler(event:ProgressEvent):void
+		{
+			progressBar_download.setProgress(event.bytesLoaded, event.bytesTotal);
+		}	
+		
+ 		private function download_cancel(event:MouseEvent):void
+		{
+			fileReference.cancel();
+			progressBar_download.label = "CANCELLED";
+			button_close.visible = true;
+			button_cancel.visible = false;
+			
+			PopUpManager.removePopUp(this);
+		}			
+		
+		private function download_completeHandler(event:Event):void
+		{
+			progressBar_download.label = "DOWNLOAD COMPLETE";
+			button_close.visible = true;
+			button_cancel.visible = false;
+		}
+		
+	]]>
+	</mx:Script>	
+	
+	<mx:ProgressBar id="progressBar_download" width="90%" mode="manual" label="DOWNLOADING..." />	
+	
+	<mx:Canvas>
+		<mx:Button id="button_cancel" label="Cancel" visible="false" click="download_cancel(event)" horizontalCenter="0" />		
+		<mx:Button id="button_close" label="Close" click="{PopUpManager.removePopUp(this)}" horizontalCenter="0"/>
+	</mx:Canvas>
+	
+</mx:TitleWindow>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/3dc107b9/TourDeFlex/TourDeFlex/src/components/QuickStartWindow.mxml
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex/src/components/QuickStartWindow.mxml b/TourDeFlex/TourDeFlex/src/components/QuickStartWindow.mxml
new file mode 100644
index 0000000..e35f3bb
--- /dev/null
+++ b/TourDeFlex/TourDeFlex/src/components/QuickStartWindow.mxml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+-->
+<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()" width="100%" height="100%" verticalGap="0" styleName="qStartStyle"  >
+	
+	<mx:Script>
+	<![CDATA[
+		import mx.events.CloseEvent;
+		import mx.core.FlexSprite;
+		import mx.managers.PopUpManager;
+		import TopPanels4_fla.MainTimeline;
+		
+		public static const CLOSE_EVENT:String = "close";
+		
+		private function init():void
+		{
+			html_quickStart.htmlLoader.navigateInSystemBrowser = true;
+			html_quickStart.htmlText = "<BR><BR><BR><CENTER>Loading...</CENTER>";
+			this.systemManager.addEventListener(MouseEvent.CLICK, modal_click);		
+		}		
+		
+		private function modal_click(event:MouseEvent):void
+		{
+			if(event.target is FlexSprite && FlexSprite(event.target).name == "modalWindow")
+				PopUpManager.removePopUp(this);
+		}
+		
+		public function set location(value:String):void
+		{
+			if(html_quickStart)
+				html_quickStart.location = value;
+		}
+		
+		public function clearContents():void
+		{
+			html_quickStart.htmlText = "";
+		}
+	]]>
+	</mx:Script>
+	
+	<mx:Style>
+		.qStartStyle{
+			backgroundImage: Embed(skinClass='QuickStartPanel');
+			backgroundSize: "100%";
+		}
+		.closeHTML{
+			skin: Embed(skinClass='CloseHTMLButton');
+		}
+		.linkButton{
+			icon: Embed(skinClass='LinkIcon');
+			color: #314983;
+			textRollOverColor: #323232;
+			fontWeight: normal;
+		}
+	</mx:Style>
+
+	<mx:Metadata>
+		[Event(name="close", type="mx.events.CloseEvent")]
+	</mx:Metadata>
+	
+	<mx:VBox height="100%" width="100%" paddingBottom="5" paddingLeft="6" paddingRight="6" paddingTop="5">
+		<mx:HTML id="html_quickStart" height="100%" width="100%" horizontalScrollPolicy="off" />
+	</mx:VBox>		
+
+
+</mx:VBox>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/3dc107b9/TourDeFlex/TourDeFlex/src/components/SearchWindow.mxml
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex/src/components/SearchWindow.mxml b/TourDeFlex/TourDeFlex/src/components/SearchWindow.mxml
new file mode 100644
index 0000000..ea687ff
--- /dev/null
+++ b/TourDeFlex/TourDeFlex/src/components/SearchWindow.mxml
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+-->
+<WipeWindow xmlns="components.*" xmlns:mx="http://www.adobe.com/2006/mxml" horizontalAlign="right" creationComplete="init()">
+	
+	<mx:Script>
+	<![CDATA[		
+		//--------------------------------------------------------------------------
+		//  Imports
+		//--------------------------------------------------------------------------	
+		import classes.ObjectData;
+		import mx.core.EdgeMetrics;
+		import mx.containers.GridItem;
+		import mx.containers.GridRow;
+		import mx.utils.StringUtil;
+		import mx.events.CollectionEvent;
+		import mx.controls.CheckBox;
+
+		//--------------------------------------------------------------------------
+		//  Variables/properties
+		//--------------------------------------------------------------------------		
+		public var objectData:ObjectData;
+		public static const SEARCH_SUBMIT:String = "searchSubmit";
+
+		public function set searchTagsData(tags:Array):void
+		{
+			var tagCounter:int = 0;
+			
+			for each(var row:GridRow in grid_tags.getChildren())
+			{
+				for each(var col:GridItem in row.getChildren())
+				{
+					var checkBox:CheckBox = CheckBox(col.getChildAt(0));
+					
+					var tagTotal:String = "";
+					if(tags[tagCounter][1] && tags[tagCounter][1].toString().length > 0)
+						tagTotal = "  (" + tags[tagCounter][1] + ")";
+						
+					checkBox.label = tags[tagCounter][0] + tagTotal;
+					checkBox.data = tags[tagCounter][0];
+					checkBox.addEventListener(Event.CHANGE, checkBox_tag_change);
+					checkBox.styleName = "tagCheckBox";
+					checkBox.visible = true;			
+					tagCounter++;
+					if(tagCounter == tags.length)
+						break;
+				}
+				if(tagCounter == tags.length)
+					break;				
+			}				
+		}
+		
+		//--------------------------------------------------------------------------
+		//  Grid creation
+		//--------------------------------------------------------------------------	
+		private function init():void
+		{
+			createTagGrid();
+		}
+		
+		private function createTagGrid():void
+		{
+			for(var rows:int=0; rows<14; rows++)
+			{
+				var row:GridRow = new GridRow();
+				row.percentWidth = 100;
+				row.percentHeight = 100;			
+				
+				for(var cols:int=0; cols<4; cols++)
+				{
+					var col:GridItem = new GridItem();
+					col.percentWidth = 100;
+					col.percentHeight = 100;
+					
+					if(cols == 0 && rows == 0)
+						col.styleName = "tagGridFirstRowItem"
+					else if(rows == 0)
+						col.styleName = "tagGridFirstRow";
+					else if(cols == 0)
+						col.styleName = "tagGridFirstItem";
+					else
+						col.styleName = "tagGridItem";		
+
+					var checkBox:CheckBox = new CheckBox();
+					checkBox.visible = false;
+					
+					col.addChild(checkBox);
+					row.addChild(col);
+				}
+				grid_tags.addChild(row);
+			}
+		}
+		
+		//--------------------------------------------------------------------------
+		//  Search controls
+		//--------------------------------------------------------------------------		
+		public function clear():void
+		{
+			textInput_search.text = "";			
+			clearGridTags();
+		}
+		
+		private function button_clear_click(event:MouseEvent):void
+		{
+			objectData.filterList("");
+			clear();
+		}
+		
+		private function clearGridTags():void
+		{
+			for each(var row:GridRow in grid_tags.getChildren())
+			{
+				for each(var col:GridItem in row.getChildren())
+				{					
+					var checkBox:CheckBox = CheckBox(col.getChildAt(0));
+					checkBox.selected = false;
+				}
+			}
+		}
+		
+		private function textBox_submit(event:Event):void
+		{
+			clearGridTags();
+			
+			objectData.filterList(textInput_search.text);
+			dispatchEvent(new Event(SEARCH_SUBMIT, true));
+		}
+		
+		private function checkBox_tag_change(event:Event):void
+		{	
+			textInput_search.text = "";		
+			var searchTerms:String = "";
+			
+			for each(var row:GridRow in grid_tags.getChildren())
+			{
+				for each(var col:GridItem in row.getChildren())
+				{					
+					var checkBox:CheckBox = CheckBox(col.getChildAt(0));
+					if(checkBox.visible && checkBox.selected)
+						searchTerms += checkBox.data + " ";
+				}
+			}
+	
+			objectData.filterList(StringUtil.trim(searchTerms), true);
+			dispatchEvent(new Event(SEARCH_SUBMIT, true));			
+		}
+		
+		//--------------------------------------------------------------------------
+		//--------------------------------------------------------------------------		
+		
+	]]>
+	</mx:Script>
+	
+	<mx:Metadata>
+		[Event(name="searchSubmit", type="flash.events.Event")]
+	</mx:Metadata>
+	
+	<mx:HBox width="100%" paddingLeft="10">
+	
+		<mx:VBox>
+			<mx:Label text="Search:" styleName="headingLabel" />
+			<mx:HBox>
+				<TextBoxSearch id="textInput_search" width="240" textSubmit="textBox_submit(event)" />
+				<mx:Button id="button_clear" label="Reset" click="button_clear_click(event)" />
+			</mx:HBox>
+		</mx:VBox>
+
+		<mx:HBox width="100%" horizontalAlign="right">
+			<mx:Button click="{this.visible = false}" styleName="closeButton" />
+		</mx:HBox>
+
+	</mx:HBox>
+
+	<mx:Spacer height="5" />
+
+	<mx:VBox styleName="searchWindowTagBox" width="100%" height="100%">
+		<mx:Label text="Popular Tags:" styleName="headingLabel" />
+		<mx:Grid id="grid_tags" width="100%" height="100%" styleName="searchWindowTags" verticalGap="0" horizontalGap="0" />		
+	</mx:VBox>
+		
+</WipeWindow>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/3dc107b9/TourDeFlex/TourDeFlex/src/components/SplashWindow.mxml
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex/src/components/SplashWindow.mxml b/TourDeFlex/TourDeFlex/src/components/SplashWindow.mxml
new file mode 100644
index 0000000..28f41bd
--- /dev/null
+++ b/TourDeFlex/TourDeFlex/src/components/SplashWindow.mxml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+-->
+<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" backgroundColor="#000000" horizontalScrollPolicy="off" verticalScrollPolicy="off" remove="video_intro.stop()" >
+	
+	<mx:Script>
+	<![CDATA[
+		import mx.managers.PopUpManager;
+
+		private var videoLength:int;
+
+		private function setVolume(event:Event):void
+		{
+			if(event.target.selected)
+			{
+				video_intro.volume = 0;
+			}
+			else
+			{
+				video_intro.volume = 1;
+				video_intro.playheadTime = 0;
+				video_intro.play();
+			}
+			//so.data.mute = ev.target.selected;
+		}
+		
+		private function checkBox_skip_click(event:Event):void
+		{
+			if(event.target.selected)
+			{				
+				video_intro_complete();
+			}
+			else
+			{
+				video_intro.playheadTime = 0;
+				video_intro.play();
+			}
+			//so.data.skip = event.target.selected;
+		}
+		
+		private function video_intro_complete():void
+		{		
+			//Preferences.preferencesXml.Splash.@skip = checkBox_skip.selected.toString(); -- no longer save skip - GAW
+			video_intro.playheadTime = video_intro.totalTime;
+			video_intro.stop();
+			//PopUpManager.removePopUp(this);
+			//Preferences.save();
+		}
+		
+	]]>
+	</mx:Script>
+
+	<mx:VideoDisplay id="video_intro" width="678" height="568" source="{Config.SPLASH_URL}" 
+		autoPlay="true" borderThickness="2" borderColor="black" borderStyle="inset"
+		autoBandWidthDetection="false" bufferTime="0.1" volume="0" complete="video_intro_complete()" rollOver="panel_options.visible=true;"
+		rollOut="panel_options.visible=false;" autoRewind="false" />
+	
+	<mx:Panel id="panel_options" width="90" height="35" color="0xFFFFFF" backgroundAlpha="0.6" backgroundColor="0x000000" borderColor="0x000000" layout="horizontal" borderAlpha="0.6"
+		borderThicknessTop="1" borderThicknessBottom="10" headerHeight="10" cornerRadius="5" x="{(video_intro.width/2)-(panel_options.width/2)}"
+		y="{(video_intro.height - 70)}" horizontalAlign="center" verticalAlign="middle"  horizontalGap="20" visible="false" 
+		roundedBottomCorners="true" rollOver="panel_options.visible=true;" >		 
+		 
+		<mx:CheckBox id="checkBox_mute" label="MUTE" selected="true" click="setVolume(event);"  textRollOverColor="0x55C0FF" textSelectedColor="0xACACAC" />
+		<!-- Removed - GAW
+		<mx:VRule height="20" alpha="0.5" />
+		<mx:Button id="checkBox_skip" label="SKIP" click="checkBox_skip_click(event);" textRollOverColor="0x55C0FF" textSelectedColor="0xACACAC" />
+		-->
+	</mx:Panel>
+	
+</mx:Canvas>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/3dc107b9/TourDeFlex/TourDeFlex/src/components/TDFTabNavigator.as
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex/src/components/TDFTabNavigator.as b/TourDeFlex/TourDeFlex/src/components/TDFTabNavigator.as
new file mode 100644
index 0000000..c045973
--- /dev/null
+++ b/TourDeFlex/TourDeFlex/src/components/TDFTabNavigator.as
@@ -0,0 +1,43 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package components
+{	
+	import mx.containers.TabNavigator; 
+	
+	/**
+	 * Currently there is a known bug within flex that prevents you from simply setting the selectedIndex 
+	 * once all the children are added. This class should be used to avoid the issue. 
+	 **/
+	
+	public class TDFTabNavigator extends TabNavigator
+	{
+		public function TDFTabNavigator()
+		{
+			super();
+		} 
+		override protected function commitSelectedIndex(newIndex:int):void
+		{
+			super.commitSelectedIndex(newIndex);
+			if(tabBar.numChildren > 0)
+			{
+				tabBar.selectedIndex = newIndex;
+			}
+		}
+	}
+}
\ No newline at end of file