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/09/03 02:17:56 UTC

[23/30] Radii8 code base as accepted by IP Clearance

http://git-wip-us.apache.org/repos/asf/flex-radii8/blob/f370bfcf/Radii8Library/src/com/flexcapacitor/controller/Radiate.as
----------------------------------------------------------------------
diff --git a/Radii8Library/src/com/flexcapacitor/controller/Radiate.as b/Radii8Library/src/com/flexcapacitor/controller/Radiate.as
new file mode 100644
index 0000000..a795b4c
--- /dev/null
+++ b/Radii8Library/src/com/flexcapacitor/controller/Radiate.as
@@ -0,0 +1,8868 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 com.flexcapacitor.controller {
+	import com.flexcapacitor.components.DocumentContainer;
+	import com.flexcapacitor.components.IDocumentContainer;
+	import com.flexcapacitor.effects.core.CallMethod;
+	import com.flexcapacitor.events.HistoryEvent;
+	import com.flexcapacitor.events.HistoryEventItem;
+	import com.flexcapacitor.events.RadiateEvent;
+	import com.flexcapacitor.logging.RadiateLogTarget;
+	import com.flexcapacitor.model.AttachmentData;
+	import com.flexcapacitor.model.Device;
+	import com.flexcapacitor.model.Document;
+	import com.flexcapacitor.model.DocumentData;
+	import com.flexcapacitor.model.EventMetaData;
+	import com.flexcapacitor.model.IDocument;
+	import com.flexcapacitor.model.IDocumentData;
+	import com.flexcapacitor.model.IDocumentMetaData;
+	import com.flexcapacitor.model.IProject;
+	import com.flexcapacitor.model.IProjectData;
+	import com.flexcapacitor.model.ISavable;
+	import com.flexcapacitor.model.ImageData;
+	import com.flexcapacitor.model.InspectableClass;
+	import com.flexcapacitor.model.InspectorData;
+	import com.flexcapacitor.model.MetaData;
+	import com.flexcapacitor.model.Project;
+	import com.flexcapacitor.model.SaveResultsEvent;
+	import com.flexcapacitor.model.SavedData;
+	import com.flexcapacitor.model.Settings;
+	import com.flexcapacitor.model.StyleMetaData;
+	import com.flexcapacitor.services.IServiceEvent;
+	import com.flexcapacitor.services.WPAttachmentService;
+	import com.flexcapacitor.services.WPService;
+	import com.flexcapacitor.services.WPServiceEvent;
+	import com.flexcapacitor.tools.ITool;
+	import com.flexcapacitor.utils.ClassUtils;
+	import com.flexcapacitor.utils.DisplayObjectUtils;
+	import com.flexcapacitor.utils.SharedObjectUtils;
+	import com.flexcapacitor.utils.TypeUtils;
+	import com.flexcapacitor.utils.XMLUtils;
+	import com.flexcapacitor.utils.supportClasses.ComponentDefinition;
+	import com.flexcapacitor.utils.supportClasses.ComponentDescription;
+	import com.flexcapacitor.views.IInspector;
+	import com.google.code.flexiframe.IFrame;
+	
+	import flash.desktop.Clipboard;
+	import flash.display.Bitmap;
+	import flash.display.BitmapData;
+	import flash.display.DisplayObject;
+	import flash.display.IBitmapDrawable;
+	import flash.events.ErrorEvent;
+	import flash.events.Event;
+	import flash.events.EventDispatcher;
+	import flash.events.IEventDispatcher;
+	import flash.events.IOErrorEvent;
+	import flash.events.SecurityErrorEvent;
+	import flash.external.ExternalInterface;
+	import flash.geom.Point;
+	import flash.globalization.DateTimeStyle;
+	import flash.net.FileReference;
+	import flash.net.SharedObject;
+	import flash.system.ApplicationDomain;
+	import flash.ui.Mouse;
+	import flash.ui.MouseCursorData;
+	import flash.utils.ByteArray;
+	import flash.utils.Dictionary;
+	import flash.utils.getTimer;
+	
+	import mx.collections.ArrayCollection;
+	import mx.containers.Grid;
+	import mx.containers.GridItem;
+	import mx.containers.GridRow;
+	import mx.containers.TabNavigator;
+	import mx.controls.LinkButton;
+	import mx.core.ClassFactory;
+	import mx.core.DeferredInstanceFromFunction;
+	import mx.core.IUIComponent;
+	import mx.core.IVisualElement;
+	import mx.core.IVisualElementContainer;
+	import mx.core.UIComponent;
+	import mx.core.mx_internal;
+	import mx.effects.effectClasses.PropertyChanges;
+	import mx.graphics.ImageSnapshot;
+	import mx.graphics.SolidColor;
+	import mx.logging.AbstractTarget;
+	import mx.logging.ILogger;
+	import mx.logging.Log;
+	import mx.logging.LogEventLevel;
+	import mx.managers.ILayoutManager;
+	import mx.managers.LayoutManager;
+	import mx.printing.FlexPrintJob;
+	import mx.printing.FlexPrintJobScaleType;
+	import mx.states.AddItems;
+	import mx.styles.IStyleClient;
+	import mx.utils.ArrayUtil;
+	import mx.utils.ObjectUtil;
+	
+	import spark.components.Application;
+	import spark.components.BorderContainer;
+	import spark.components.Button;
+	import spark.components.ComboBox;
+	import spark.components.Grid;
+	import spark.components.Image;
+	import spark.components.Label;
+	import spark.components.NavigatorContent;
+	import spark.components.Scroller;
+	import spark.components.SkinnableContainer;
+	import spark.components.supportClasses.GroupBase;
+	import spark.components.supportClasses.SkinnableTextBase;
+	import spark.components.supportClasses.TextBase;
+	import spark.core.ContentCache;
+	import spark.core.IViewport;
+	import spark.effects.SetAction;
+	import spark.formatters.DateTimeFormatter;
+	import spark.layouts.BasicLayout;
+	import spark.primitives.BitmapImage;
+	import spark.primitives.Rect;
+	import spark.skins.spark.DefaultGridItemRenderer;
+	
+	import org.as3commons.lang.ArrayUtils;
+	import org.as3commons.lang.DictionaryUtils;
+	import org.as3commons.lang.ObjectUtils;
+	
+	use namespace mx_internal;
+	
+	/**
+	 * Dispatched when register results are received
+	 * */
+	[Event(name="registerResults", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when a print job is cancelled
+	 * */
+	[Event(name="printCancelled", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when an item is added to the target
+	 * */
+	[Event(name="addItem", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when an item is removed from the target
+	 * */
+	[Event(name="removeItem", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when an item is removed from the target
+	 * */
+	[Event(name="removeTarget", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when the target is changed
+	 * */
+	[Event(name="targetChange", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when the document is changed
+	 * */
+	[Event(name="documentChange", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when a document is opening
+	 * */
+	[Event(name="documentOpening", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when a document is opened
+	 * */
+	[Event(name="documentOpen", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when a document is renamed
+	 * */
+	[Event(name="documentRename", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when the project is changed
+	 * */
+	[Event(name="projectChange", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when the project is deleted
+	 * */
+	[Event(name="projectDeletedResults", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when the project is created
+	 * */
+	[Event(name="projectCreated", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when a property on the target is changed. 
+	 * Using propertyChanged instead of propertyChange because of error with bindable
+	 * tag using propertyChange:
+	 * TypeError: Error #1034: Type Coercion failed: cannot convert mx.events::PropertyChangeEvent@11d2187b1 to com.flexcapacitor.events.RadiateEvent.
+	 * */
+	[Event(name="propertyChanged", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when a property is selected on the target
+	 * */
+	[Event(name="propertySelected", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when a property edit is requested
+	 * */
+	[Event(name="propertyEdit", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when the tool changes
+	 * */
+	[Event(name="toolChange", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when the scale changes
+	 * */
+	[Event(name="scaleChange", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when the document size or scale changes
+	 * */
+	[Event(name="documentSizeChange", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Not used yet. 
+	 * */
+	[Event(name="initialized", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Used when the tools list has been updated. 
+	 * */
+	[Event(name="toolsUpdated", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Used when the components list is updated. 
+	 * */
+	[Event(name="componentsUpdated", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Used when the document canvas is updated. 
+	 * */
+	[Event(name="canvasChange", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Event to request a preview if available. Used for HTML preview. 
+	 * */
+	[Event(name="requestPreview", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when the generated code is updated. 
+	 * */
+	[Event(name="codeUpdated", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when a color is selected. 
+	 * */
+	[Event(name="colorSelected", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Dispatched when an object is selected 
+	 * */
+	[Event(name="objectSelected", type="com.flexcapacitor.radiate.events.RadiateEvent")]
+	
+	/**
+	 * Main class and API that handles the interactions between the view and the models. 
+	 * 
+	 * Dispatches events and exposes methods to manipulate the documents.
+	 *  
+	 * It contains a list of components, tools, devices, inspectors (panels), assets and 
+	 * in the future we should add skins, effects and so on. 
+	 * These items are created from an XML file at startup so we can configure what is available
+	 * to our user or project. We do this so we can also load in a remote SWF to add 
+	 * additional components, sounds, images, skins, inspectors, fonts, etc
+	 * 
+	 * Currently we are saving and loading to a remote location or to a local shared object. 
+	 * To save to a local file system we will need to modify these functions. 
+	 * 
+	 * This class supports an Undo / Redo history. The architecture is loosely based on 
+	 * the structure found in the Effects classes. We may want to be a proxy to the documents
+	 * and call undo and redo on them since we would like to support more than one 
+	 * type of document. 
+	 * 
+	 * This class can be broken up into multiple classes since it is also handling 
+	 * saving and loading and services. 
+	 * 
+	 * To set a property or style call setProperty or setStyle. 
+	 * To add a component call addElement. 
+	 * To log a message to the console call Radiate.log.info() or error().
+	 * 
+	 * To undo call undo
+	 * To redo call redo
+	 * 
+	 * To get the history index access history index
+	 * To check if history exists call the has history
+	 * To check if undo can be performed access has undo
+	 * To check if redo can be performed access has redo 
+	 * 
+	 * Editing through cut, copy and paste is only partially implemented. 
+	 * */
+	public class Radiate extends EventDispatcher {
+		
+		public static const SAME_OWNER:String = "sameOwner";
+		public static const SAME_PARENT:String = "sameParent";
+		public static const ADDED:String = "added";
+		public static const MOVED:String = "moved";
+		public static const REMOVED:String = "removed";
+		public static const ADD_ERROR:String = "addError";
+		public static const REMOVE_ERROR:String = "removeError";
+		public static const RADIATE_LOG:String = "radiate";
+		public static const LOGGED_IN:String = "loggedIn";
+		public static const LOGGED_OUT:String = "loggedOut";
+		
+		public function Radiate(s:SINGLEDOUBLE) {
+			super(target as IEventDispatcher);
+			
+			// Create a target
+			setLoggingTarget(defaultLogTarget);
+			
+			
+			// initialize - maybe call on startup() instead
+			initialize();
+		}
+		
+		//----------------------------------
+		//  instance
+		//----------------------------------
+		private static var _instance:Radiate;
+		
+		/**
+		 * Attempt to support a console part 2
+		 * */
+		public static function get log():ILogger {
+			
+			if (_log) {
+				return _log;
+			}
+			else {
+				setLoggingTarget(defaultLogTarget);
+				return _log;
+			}
+		}
+
+		/**
+		 * @private
+		 */
+		public static function set log(value:ILogger):void {
+			_log = value;
+		}
+
+		/**
+		 * Attempt to support a console part 3
+		 * */
+		public static function get console():Object {
+			return _console;
+		}
+
+		/**
+		 * @private
+		 */
+		public static function set console(value:Object):void {
+			_console = value;
+			
+			if ("console" in logTarget) {
+				logTarget["console"] = value;
+			}
+		}
+
+		public static function get instance():Radiate
+		{
+			if (!_instance) {
+				_instance = new Radiate(new SINGLEDOUBLE());
+			}
+			return _instance;
+		}
+		
+		public static function getInstance():Radiate {
+			return instance;
+		}
+		
+		/**
+		 * Create references for classes we need.
+		 * */
+		public static var radiateReferences:RadiateReferences;
+		
+		/**
+		 * If true then importing document
+		 * */
+		public static var importingDocument:Boolean;
+		
+		/**
+		 * Upload attachment
+		 * */
+		public var uploadAttachmentService:WPAttachmentService;
+		
+		/**
+		 * Service to get list of attachments
+		 * */
+		public var getAttachmentsService:WPService;
+		
+		/**
+		 * Service to get list of projects
+		 * */
+		public var getProjectsService:WPService;
+		
+		/**
+		 * Service to delete attachment
+		 * */
+		public var deleteAttachmentService:WPService;
+		
+		/**
+		 * Service to delete document
+		 * */
+		public var deleteDocumentService:WPService;
+		
+		/**
+		 * Service to delete project
+		 * */
+		public var deleteProjectService:WPService;
+		
+		/**
+		 * Service to request reset the password
+		 * */
+		public var lostPasswordService:WPService;
+		
+		/**
+		 * Service to change the password
+		 * */
+		public var changePasswordService:WPService;
+		
+		/**
+		 * Service to login
+		 * */
+		public var loginService:WPService;
+		
+		/**
+		 * Service to logout
+		 * */
+		public var logoutService:WPService;
+		
+		/**
+		 * Service to register
+		 * */
+		public var registerService:WPService;
+		
+		/**
+		 * Service to check if user is logged in
+		 * */
+		public var getLoggedInStatusService:WPService;
+		
+		/**
+		 * Set to true when a document is being saved to the server
+		 * */
+		[Bindable]
+		public var saveDocumentInProgress:Boolean;
+		
+		/**
+		 * Set to true when project is being saved to the server
+		 * */
+		[Bindable]
+		public var saveProjectInProgress:Boolean;
+		
+		/**
+		 * Set to true when checking if user is logged in
+		 * */
+		[Bindable]
+		public var getLoggedInStatusInProgress:Boolean;
+		
+		/**
+		 * Set to true when lost password call is made
+		 * */
+		[Bindable]
+		public var lostPasswordInProgress:Boolean;
+		
+		/**
+		 * Set to true when changing password
+		 * */
+		[Bindable]
+		public var changePasswordInProgress:Boolean;
+		
+		/**
+		 * Set to true when registering
+		 * */
+		[Bindable]
+		public var registerInProgress:Boolean;
+		
+		/**
+		 * Set to true when logging in
+		 * */
+		[Bindable]
+		public var loginInProgress:Boolean;
+		
+		/**
+		 * Set to true when logging out
+		 * */
+		[Bindable]
+		public var logoutInProgress:Boolean;
+		
+		/**
+		 * Set to true when deleting a project
+		 * */
+		[Bindable]
+		public var deleteProjectInProgress:Boolean;
+		
+		/**
+		 * Set to true when deleting a document
+		 * */
+		[Bindable]
+		public var deleteDocumentInProgress:Boolean;
+		
+		/**
+		 * Set to true when deleting an attachment
+		 * */
+		[Bindable]
+		public var deleteAttachmentInProgress:Boolean;
+		
+		/**
+		 * Set to true when getting list of attachments
+		 * */
+		[Bindable]
+		public var getAttachmentsInProgress:Boolean;
+		
+		/**
+		 * Set to true when uploading an attachment
+		 * */
+		[Bindable]
+		public var uploadAttachmentInProgress:Boolean;
+		
+		/**
+		 * Set to true when getting list of projects
+		 * */
+		[Bindable]
+		public var getProjectsInProgress:Boolean;
+		
+		/**
+		 * Is user logged in
+		 * */
+		[Bindable]
+		public var isUserLoggedIn:Boolean;
+		
+		/**
+		 * Default storage location for save and load. 
+		 * */
+		[Bindable]
+		public var defaultStorageLocation:String;
+		
+		/**
+		 * Can user connect to the service
+		 * */
+		[Bindable]
+		public var isUserConnected:Boolean;
+		
+		/**
+		 * Avatar of user
+		 * */
+		[Bindable]
+		public var userAvatar:String = "assets/images/icons/gravatar.png";
+		
+		/**
+		 * Path to default avatar of user (from Gravatar)
+		 * Gravatars icons don't work locally so using path. 
+		 * Default - http://0.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?s=96
+		 * local - assets/images/icons/gravatar.png
+		 * */
+		[Bindable]
+		public var defaultUserAvatarPath:String = "assets/images/icons/gravatar.png";
+		
+		/**
+		 * User info
+		 * */
+		[Bindable]
+		public var user:Object;
+		
+		/**
+		 * User email
+		 * */
+		[Bindable]
+		public var userEmail:String;
+		
+		/**
+		 * User id
+		 * */
+		[Bindable]
+		public var userID:int = -1;
+		
+		/**
+		 * User sites
+		 * */
+		[Bindable]
+		public var userSites:Array = [];
+		
+		/**
+		 * User site path
+		 * */
+		[Bindable]
+		public var userSitePath:String;
+		
+		/**
+		 * User display name
+		 * */
+		[Bindable]
+		public var userDisplayName:String = "guest";
+		
+		/**
+		 * Last save date
+		 * */
+		[Bindable]
+		public var lastSaveDate:String;
+		
+		/**
+		 * Cut data
+		 * */
+		public var cutData:Object;
+		
+		/**
+		 * Cut data
+		 * */
+		public var copiedData:Object;
+		
+		/**
+		 * Auto save locations
+		 * */
+		[Bindable]
+		public var autoSaveLocations:String;
+		
+		private var _enableAutoSave:Boolean;
+
+		[Bindable]
+		/**
+		 * Auto save enabled
+		 * */
+		public function get enableAutoSave():Boolean {
+			return _enableAutoSave;
+		}
+
+		/**
+		 * @private
+		 */
+		public function set enableAutoSave(value:Boolean):void {
+			_enableAutoSave = value;
+			
+			
+			if (value) {
+				if (!autoSaveEffect) {
+					autoSaveEffect =  new CallMethod();
+					autoSaveEffect.method = autoSaveHandler;
+					autoSaveEffect.repeatCount = 0;
+					autoSaveEffect.repeatDelay = autoSaveInterval;
+				}
+				if (!autoSaveEffect.isPlaying) {
+					autoSaveEffect.play();
+				}
+			}
+			else {
+				autoSaveEffect.stop();
+			}
+		}
+		
+		/**
+		 * Interval to check to save project
+		 * */
+		public var autoSaveInterval:int = 30000;
+		
+		/**
+		 * Effect to auto save
+		 * */
+		public var autoSaveEffect:CallMethod;
+		
+		/**
+		 * Handle auto saving 
+		 * */
+		public function autoSaveHandler():void {
+			var length:int;
+			var iProject:IProject;
+			var iDocumentData:IDocumentData;
+			var iAttachmentData:AttachmentData;
+			var imageData:ImageData;
+			var i:int;
+			
+			// save documents
+			/*length = documents.length;
+			for (i=0;i<length;i++) {
+				iDocumentData = documents[i] as IDocumentData;
+				if (iDocumentData.isChanged && !iDocumentData.saveInProgress && iDocumentData.isOpen) {
+					iDocumentData.save();
+				}
+			}*/
+			
+			// save projects
+			length = projects.length;
+			for (i=0;i<length;i++) {
+				iDocumentData = projects[i] as IDocumentData;
+				//if (iDocumentData.isChanged && !iDocumentData.saveInProgress && iDocumentData.isOpen) {
+				if (!iDocumentData.saveInProgress && iDocumentData.isOpen) {
+					iDocumentData.save();
+				}
+			}
+			
+			// save attachments
+			length = assets.length;
+			for (i=0;i<length;i++) {
+				iAttachmentData = assets[i] as ImageData;
+				if (iAttachmentData) {
+					imageData = iAttachmentData as ImageData;
+					
+					if (!imageData.saveInProgress && imageData.id==null) {
+						//imageData.save();
+						uploadAttachment(imageData.byteArray, selectedProject.id, imageData.name, null, imageData.contentType);
+					}
+				}
+			}
+		}
+
+		/**
+		 * Build number
+		 * */
+		[Bindable]
+		public var buildNumber:String;
+		
+		/**
+		 * Build date
+		 * */
+		[Bindable]
+		public var buildDate:String;
+		
+		/**
+		 * Build time
+		 * */
+		[Bindable]
+		public var buildTime:String;
+		
+		//----------------------------------
+		//
+		//  Events Management
+		// 
+		//----------------------------------
+		
+		/**
+		 * Dispatch attachments received event
+		 * */
+		public function dispatchGetProjectsListResultsEvent(data:Object):void {
+			var projectsListResultEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECTS_LIST_RECEIVED);
+			
+			if (hasEventListener(RadiateEvent.PROJECTS_LIST_RECEIVED)) {
+				projectsListResultEvent.data = data;
+				dispatchEvent(projectsListResultEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch print cancelled event
+		 * */
+		public function dispatchPrintCancelledEvent(data:Object, printJob:FlexPrintJob):void {
+			var printCancelledEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PRINT_CANCELLED);
+			
+			if (hasEventListener(RadiateEvent.PRINT_CANCELLED)) {
+				printCancelledEvent.data = data;
+				printCancelledEvent.selectedItem = printJob;
+				dispatchEvent(printCancelledEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch print complete event
+		 * */
+		public function dispatchPrintCompleteEvent(data:Object, printJob:FlexPrintJob):void {
+			var printCompleteEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PRINT_COMPLETE);
+			
+			if (hasEventListener(RadiateEvent.PRINT_COMPLETE)) {
+				printCompleteEvent.data = data;
+				printCompleteEvent.selectedItem = printJob;
+				dispatchEvent(printCompleteEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch attachments received event
+		 * */
+		public function dispatchLoginStatusEvent(loggedIn:Boolean, data:Object):void {
+			var loggedInStatusEvent:RadiateEvent = new RadiateEvent(RadiateEvent.LOGGED_IN_STATUS);
+			
+			if (hasEventListener(RadiateEvent.LOGGED_IN_STATUS)) {
+				loggedInStatusEvent.status = loggedIn ? LOGGED_IN : LOGGED_OUT;
+				loggedInStatusEvent.data = data;
+				dispatchEvent(loggedInStatusEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch attachments received event
+		 * */
+		public function dispatchAttachmentsResultsEvent(successful:Boolean, attachments:Array):void {
+			var attachmentsReceivedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.ATTACHMENTS_RECEIVED, false, false, attachments);
+			
+			if (hasEventListener(RadiateEvent.ATTACHMENTS_RECEIVED)) {
+				attachmentsReceivedEvent.successful = successful;
+				attachmentsReceivedEvent.status = successful ? "ok" : "fault";
+				attachmentsReceivedEvent.targets = ArrayUtil.toArray(attachments);
+				dispatchEvent(attachmentsReceivedEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch upload attachment received event
+		 * */
+		public function dispatchUploadAttachmentResultsEvent(successful:Boolean, attachments:Array, data:Object):void {
+			var uploadAttachmentEvent:RadiateEvent = new RadiateEvent(RadiateEvent.ATTACHMENT_UPLOADED, false, false);
+			
+			if (hasEventListener(RadiateEvent.ATTACHMENT_UPLOADED)) {
+				uploadAttachmentEvent.successful = successful;
+				uploadAttachmentEvent.status = successful ? "ok" : "fault";
+				uploadAttachmentEvent.data = attachments;
+				uploadAttachmentEvent.selectedItem = data;
+				dispatchEvent(uploadAttachmentEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch login results event
+		 * */
+		public function dispatchLoginResultsEvent(successful:Boolean, data:Object):void {
+			var loginResultsEvent:RadiateEvent = new RadiateEvent(RadiateEvent.LOGIN_RESULTS);
+			
+			if (hasEventListener(RadiateEvent.LOGIN_RESULTS)) {
+				loginResultsEvent.data = data;
+				loginResultsEvent.successful = successful;
+				dispatchEvent(loginResultsEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch logout results event
+		 * */
+		public function dispatchLogoutResultsEvent(successful:Boolean, data:Object):void {
+			var logoutResultsEvent:RadiateEvent = new RadiateEvent(RadiateEvent.LOGOUT_RESULTS);
+			
+			if (hasEventListener(RadiateEvent.LOGOUT_RESULTS)) {
+				logoutResultsEvent.data = data;
+				logoutResultsEvent.successful = successful;
+				dispatchEvent(logoutResultsEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch register results event
+		 * */
+		public function dispatchRegisterResultsEvent(successful:Boolean, data:Object):void {
+			var registerResultsEvent:RadiateEvent = new RadiateEvent(RadiateEvent.REGISTER_RESULTS);
+			
+			if (hasEventListener(RadiateEvent.REGISTER_RESULTS)) {
+				registerResultsEvent.data = data;
+				registerResultsEvent.successful = successful;
+				dispatchEvent(registerResultsEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch change password results event
+		 * */
+		public function dispatchChangePasswordResultsEvent(successful:Boolean, data:Object):void {
+			var changePasswordResultsEvent:RadiateEvent = new RadiateEvent(RadiateEvent.CHANGE_PASSWORD_RESULTS);
+			
+			if (hasEventListener(RadiateEvent.CHANGE_PASSWORD_RESULTS)) {
+				changePasswordResultsEvent.data = data;
+				changePasswordResultsEvent.successful = successful;
+				dispatchEvent(changePasswordResultsEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch lost password results event
+		 * */
+		public function dispatchLostPasswordResultsEvent(successful:Boolean, data:Object):void {
+			var lostPasswordResultsEvent:RadiateEvent = new RadiateEvent(RadiateEvent.LOST_PASSWORD_RESULTS);
+			
+			if (hasEventListener(RadiateEvent.LOST_PASSWORD_RESULTS)) {
+				lostPasswordResultsEvent.data = data;
+				lostPasswordResultsEvent.successful = successful;
+				dispatchEvent(lostPasswordResultsEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch project deleted results event
+		 * */
+		public function dispatchProjectDeletedEvent(successful:Boolean, data:Object):void {
+			var deleteProjectResultsEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECT_DELETED);
+			
+			if (hasEventListener(RadiateEvent.PROJECT_DELETED)) {
+				deleteProjectResultsEvent.data = data;
+				deleteProjectResultsEvent.successful = successful;
+				deleteProjectResultsEvent.status = successful ? "ok" : "error";
+				dispatchEvent(deleteProjectResultsEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch document deleted results event
+		 * */
+		public function dispatchDocumentDeletedEvent(successful:Boolean, data:Object):void {
+			var deleteDocumentResultsEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_DELETED);
+			
+			if (hasEventListener(RadiateEvent.DOCUMENT_DELETED)) {
+				deleteDocumentResultsEvent.data = data;
+				deleteDocumentResultsEvent.successful = successful;
+				deleteDocumentResultsEvent.status = successful ? "ok" : "error";
+				dispatchEvent(deleteDocumentResultsEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch asset added event
+		 * */
+		public function dispatchAssetAddedEvent(data:Object):void {
+			var assetAddedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.ASSET_ADDED);
+			
+			if (hasEventListener(RadiateEvent.ASSET_ADDED)) {
+				assetAddedEvent.data = data;
+				dispatchEvent(assetAddedEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch asset removed event
+		 * */
+		public function dispatchAssetRemovedEvent(data:IDocumentData, successful:Boolean = true):void {
+			var assetRemovedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.ASSET_REMOVED);
+			
+			if (hasEventListener(RadiateEvent.ASSET_REMOVED)) {
+				assetRemovedEvent.data = data;
+				dispatchEvent(assetRemovedEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch target change event
+		 * */
+		public function dispatchTargetChangeEvent(target:*, multipleSelection:Boolean = false):void {
+			if (importingDocument) return;
+			var targetChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.TARGET_CHANGE, false, false, target, null, null, multipleSelection);
+			
+			if (hasEventListener(RadiateEvent.TARGET_CHANGE)) {
+				targetChangeEvent.selectedItem = target && target is Array ? target[0] : target;
+				targetChangeEvent.targets = ArrayUtil.toArray(target);
+				dispatchEvent(targetChangeEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch scale change event
+		 * */
+		public function dispatchScaleChangeEvent(target:*, scaleX:Number = NaN, scaleY:Number = NaN):void {
+			var scaleChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.SCALE_CHANGE, false, false, target, null, null);
+			
+			if (hasEventListener(RadiateEvent.SCALE_CHANGE)) {
+				scaleChangeEvent.scaleX = scaleX;
+				scaleChangeEvent.scaleY = scaleY;
+				dispatchEvent(scaleChangeEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch document size change event
+		 * */
+		public function dispatchDocumentSizeChangeEvent(target:*):void {
+			var scaleChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_SIZE_CHANGE, false, false, target, null, null);
+			
+			if (hasEventListener(RadiateEvent.DOCUMENT_SIZE_CHANGE)) {
+				dispatchEvent(scaleChangeEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch preview event
+		 * */
+		public function dispatchPreviewEvent(code:String, type:String):void {
+			var previewEvent:RadiateEvent = new RadiateEvent(RadiateEvent.REQUEST_PREVIEW);
+			
+			if (hasEventListener(RadiateEvent.REQUEST_PREVIEW)) {
+				previewEvent.previewType = type;
+				previewEvent.value = code;
+				dispatchEvent(previewEvent);
+			}
+		}
+		
+		
+		/**
+		 * Dispatch code updated event. Type is usually "HTML". 
+		 * */
+		public function dispatchCodeUpdatedEvent(code:String, type:String, openInWindow:Boolean = false):void {
+			var codeUpdatedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.CODE_UPDATED);
+			
+			if (hasEventListener(RadiateEvent.CODE_UPDATED)) {
+				codeUpdatedEvent.previewType = type;
+				codeUpdatedEvent.value = code;
+				codeUpdatedEvent.openInBrowser = openInWindow;
+				dispatchEvent(codeUpdatedEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch color selected event
+		 * */
+		public function dispatchColorSelectedEvent(color:uint, invalid:Boolean = false):void {
+			var colorSelectedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.COLOR_SELECTED);
+			
+			if (hasEventListener(RadiateEvent.COLOR_SELECTED)) {
+				colorSelectedEvent.color = color;
+				colorSelectedEvent.invalid = invalid;
+				dispatchEvent(colorSelectedEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch property selected event
+		 * */
+		public function dispatchPropertySelectedEvent(property:String, node:MetaData = null):void {
+			var colorSelectedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROPERTY_SELECTED);
+			
+			if (hasEventListener(RadiateEvent.PROPERTY_SELECTED)) {
+				colorSelectedEvent.property = property;
+				colorSelectedEvent.selectedItem = node;
+				dispatchEvent(colorSelectedEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch color preview event
+		 * */
+		public function dispatchColorPreviewEvent(color:uint, invalid:Boolean = false):void {
+			var colorPreviewEvent:RadiateEvent = new RadiateEvent(RadiateEvent.COLOR_PREVIEW);
+			
+			if (hasEventListener(RadiateEvent.COLOR_PREVIEW)) {
+				colorPreviewEvent.color = color;
+				colorPreviewEvent.invalid = invalid;
+				dispatchEvent(colorPreviewEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch canvas change event
+		 * */
+		public function dispatchCanvasChangeEvent(canvas:*, canvasBackgroundParent:*, scroller:Scroller):void {
+			var targetChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.CANVAS_CHANGE);
+			
+			if (hasEventListener(RadiateEvent.CANVAS_CHANGE)) {
+				dispatchEvent(targetChangeEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch tool change event
+		 * */
+		public function dispatchToolChangeEvent(value:ITool):void {
+			var toolChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.TOOL_CHANGE);
+			
+			if (hasEventListener(RadiateEvent.TOOL_CHANGE)) {
+				toolChangeEvent.selectedItem = target && target is Array ? target[0] : target;
+				toolChangeEvent.targets = targets;
+				toolChangeEvent.tool = value;
+				dispatchEvent(toolChangeEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch target change event with a null target. 
+		 * */
+		public function dispatchTargetClearEvent():void {
+			var targetChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.TARGET_CHANGE);
+			
+			if (hasEventListener(RadiateEvent.TARGET_CHANGE)) {
+				dispatchEvent(targetChangeEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch property change event
+		 * */
+		public function dispatchPropertyChangeEvent(target:*, changes:Array, properties:Array, multipleSelection:Boolean = false):void {
+			if (importingDocument) return;
+			var propertyChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROPERTY_CHANGED, false, false, target, changes, properties, multipleSelection);
+			
+			if (hasEventListener(RadiateEvent.PROPERTY_CHANGED)) {
+				propertyChangeEvent.properties = properties;
+				propertyChangeEvent.changes = changes;
+				propertyChangeEvent.multipleSelection = multipleSelection;
+				propertyChangeEvent.selectedItem = target && target is Array ? target[0] : target;
+				propertyChangeEvent.targets = ArrayUtil.toArray(target);
+				dispatchEvent(propertyChangeEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch object selected event
+		 * */
+		public function dispatchObjectSelectedEvent(target:*):void {
+			var objectSelectedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.OBJECT_SELECTED, false, false, target);
+			
+			if (hasEventListener(RadiateEvent.OBJECT_SELECTED)) {
+				dispatchEvent(objectSelectedEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch add items event
+		 * */
+		public function dispatchAddEvent(target:*, changes:Array, properties:Array, multipleSelection:Boolean = false):void {
+			if (importingDocument) return;
+			var event:RadiateEvent = new RadiateEvent(RadiateEvent.ADD_ITEM, false, false, target, changes, properties, multipleSelection);
+			var length:int = changes ? changes.length : 0;
+			
+			if (hasEventListener(RadiateEvent.ADD_ITEM)) {
+				event.properties = properties;
+				event.changes = changes;
+				event.multipleSelection = multipleSelection;
+				event.selectedItem = target && target is Array ? target[0] : target;
+				event.targets = ArrayUtil.toArray(target);
+				
+				for (var i:int;i<length;i++) {
+					if (changes[i] is AddItems) {
+						event.addItemsInstance = changes[i];
+						event.moveItemsInstance = changes[i];
+					}
+				}
+				dispatchEvent(event);
+			}
+		}
+		
+		/**
+		 * Dispatch add items event
+		 * */
+		public function dispatchMoveEvent(target:*, changes:Array, properties:Array, multipleSelection:Boolean = false):void {
+			if (importingDocument) return;
+			var event:RadiateEvent = new RadiateEvent(RadiateEvent.MOVE_ITEM, false, false, target, changes, properties, multipleSelection);
+			var length:int = changes ? changes.length : 0;
+			
+			if (hasEventListener(RadiateEvent.MOVE_ITEM)) {
+				event.properties = properties;
+				event.changes = changes;
+				event.multipleSelection = multipleSelection;
+				event.selectedItem = target && target is Array ? target[0] : target;
+				event.targets = ArrayUtil.toArray(target);
+				
+				for (var i:int;i<length;i++) {
+					if (changes[i] is AddItems) {
+						event.addItemsInstance = changes[i];
+						event.moveItemsInstance = changes[i];
+					}
+				}
+				dispatchEvent(event);
+			}
+		}
+		
+		/**
+		 * Dispatch remove items event
+		 * */
+		public function dispatchRemoveItemsEvent(target:*, changes:Array, properties:*, multipleSelection:Boolean = false):void {
+			var event:RadiateEvent = new RadiateEvent(RadiateEvent.REMOVE_ITEM, false, false, target, changes, properties, multipleSelection);
+			var length:int = changes ? changes.length : 0;
+			
+			if (hasEventListener(RadiateEvent.REMOVE_ITEM)) {
+				event.properties = properties;
+				event.changes = changes;
+				event.multipleSelection = multipleSelection;
+				event.selectedItem = target && target is Array ? target[0] : target;
+				event.targets = ArrayUtil.toArray(target);
+				
+				for (var i:int;i<length;i++) {
+					if (changes[i] is AddItems) {
+						event.addItemsInstance = changes[i];
+						event.moveItemsInstance = changes[i];
+					}
+				}
+				dispatchEvent(event);
+			}
+		}
+		
+		/**
+		 * Dispatch to invoke property edit event
+		 * */
+		public function dispatchTargetPropertyEditEvent(target:Object, changes:Array, properties:Array, multipleSelection:Boolean = false):void {
+			var propertyEditEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROPERTY_EDIT, false, false, target, changes, properties, null, multipleSelection);
+			
+			if (hasEventListener(RadiateEvent.PROPERTY_EDIT)) {
+				dispatchEvent(propertyEditEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch document change event
+		 * */
+		public function dispatchDocumentChangeEvent(document:IDocument):void {
+			var documentChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_CHANGE, false, false, document);
+			
+			if (hasEventListener(RadiateEvent.DOCUMENT_CHANGE)) {
+				dispatchEvent(documentChangeEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch document rename event
+		 * */
+		public function dispatchDocumentRenameEvent(document:IDocument, name:String):void {
+			var documentRenameEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_RENAME, false, false, document);
+			
+			if (hasEventListener(RadiateEvent.DOCUMENT_RENAME)) {
+				dispatchEvent(documentRenameEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch project rename event
+		 * */
+		public function dispatchProjectRenameEvent(project:IProject, name:String):void {
+			var projectRenameEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECT_RENAME, false, false, project);
+			
+			if (hasEventListener(RadiateEvent.PROJECT_RENAME)) {
+				dispatchEvent(projectRenameEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch documents set
+		 * */
+		public function dispatchDocumentsSetEvent(documents:Array):void {
+			var documentChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENTS_SET, false, false, documents);
+			
+			if (hasEventListener(RadiateEvent.DOCUMENTS_SET)) {
+				dispatchEvent(documentChangeEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch document opening event
+		 * */
+		public function dispatchDocumentOpeningEvent(document:IDocument, isPreview:Boolean = false):Boolean {
+			var documentOpeningEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_OPENING, false, true, document);
+			var dispatched:Boolean;
+			
+			if (hasEventListener(RadiateEvent.DOCUMENT_OPENING)) {
+				dispatched = dispatchEvent(documentOpeningEvent);
+			}
+			
+			return dispatched;
+		}
+		
+		/**
+		 * Dispatch document open event
+		 * */
+		public function dispatchDocumentOpenEvent(document:IDocument):void {
+			var documentOpenEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_OPEN, false, false);
+			
+			if (hasEventListener(RadiateEvent.DOCUMENT_OPEN)) {
+				documentOpenEvent.selectedItem = document;
+				dispatchEvent(documentOpenEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch document removed event
+		 * */
+		public function dispatchDocumentRemovedEvent(document:IDocument, successful:Boolean = true):void {
+			var documentRemovedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_REMOVED, false, false);
+			
+			if (hasEventListener(RadiateEvent.DOCUMENT_REMOVED)) {
+				documentRemovedEvent.successful = successful;
+				documentRemovedEvent.selectedItem = document;
+				dispatchEvent(documentRemovedEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch document save as complete event
+		 * */
+		public function dispatchProjectSavedEvent(project:IProject):void {
+			var projectSaveEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECT_SAVED, false, false);
+			
+			if (hasEventListener(RadiateEvent.PROJECT_SAVED)) {
+				
+				projectSaveEvent.selectedItem = project;
+				dispatchEvent(projectSaveEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch document save complete event
+		 * */
+		public function dispatchDocumentSaveCompleteEvent(document:IDocument):void {
+			var documentSaveAsCompleteEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_SAVE_COMPLETE, false, false, document);
+			
+			if (hasEventListener(RadiateEvent.DOCUMENT_SAVE_COMPLETE)) {
+				dispatchEvent(documentSaveAsCompleteEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch document not saved event
+		 * */
+		public function dispatchDocumentSaveFaultEvent(document:IDocument):void {
+			var documentSaveFaultEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_SAVE_FAULT, false, false, document);
+			
+			if (hasEventListener(RadiateEvent.DOCUMENT_SAVE_FAULT)) {
+				dispatchEvent(documentSaveFaultEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch document save as cancel event
+		 * */
+		public function dispatchDocumentSaveAsCancelEvent(document:IDocument):void {
+			var documentSaveAsCancelEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_SAVE_AS_CANCEL, false, false, document);
+			
+			if (hasEventListener(RadiateEvent.DOCUMENT_SAVE_AS_CANCEL)) {
+				dispatchEvent(documentSaveAsCancelEvent);
+			}
+		}
+		
+		
+		/**
+		 * Dispatch document add event
+		 * */
+		public function dispatchDocumentAddedEvent(document:IDocument):void {
+			var documentAddedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_ADDED, false, false, document, null, null);
+			
+			if (hasEventListener(RadiateEvent.DOCUMENT_ADDED)) {
+				dispatchEvent(documentAddedEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch project closing event
+		 * */
+		public function dispatchProjectClosingEvent(project:IProject):void {
+			var projectClosingEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECT_CLOSING, false, false, project, null, null);
+			
+			if (hasEventListener(RadiateEvent.PROJECT_CLOSING)) {
+				dispatchEvent(projectClosingEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch project closed event
+		 * */
+		public function dispatchProjectOpenedEvent(project:IProject):void {
+			var projectOpenedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECT_OPENED, false, false, project, null, null);
+			
+			if (hasEventListener(RadiateEvent.PROJECT_OPENED)) {
+				dispatchEvent(projectOpenedEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch project closed event
+		 * */
+		public function dispatchProjectClosedEvent(project:IProject):void {
+			var projectClosedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECT_CLOSED, false, false, project, null, null);
+			
+			if (hasEventListener(RadiateEvent.PROJECT_CLOSED)) {
+				dispatchEvent(projectClosedEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch project removed event
+		 * */
+		public function dispatchProjectRemovedEvent(project:IProject):void {
+			var projectRemovedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECT_REMOVED, false, false, project, null, null);
+			
+			if (hasEventListener(RadiateEvent.PROJECT_REMOVED)) {
+				dispatchEvent(projectRemovedEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch project change event
+		 * */
+		public function dispatchProjectChangeEvent(project:IProject, multipleSelection:Boolean = false):void {
+			var projectChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECT_CHANGE, false, false, project, null, null, multipleSelection);
+			
+			if (hasEventListener(RadiateEvent.PROJECT_CHANGE)) {
+				dispatchEvent(projectChangeEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch projects set event
+		 * */
+		public function dispatchProjectsSetEvent(projects:Array, multipleSelection:Boolean = false):void {
+			var projectChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECTS_SET, false, false, projects, null, null, multipleSelection);
+			
+			if (hasEventListener(RadiateEvent.PROJECTS_SET)) {
+				dispatchEvent(projectChangeEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch project created event
+		 * */
+		public function dispatchProjectAddedEvent(project:IProject):void {
+			var projectCreatedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECT_ADDED, false, false, project, null, null);
+			
+			if (hasEventListener(RadiateEvent.PROJECT_ADDED)) {
+				dispatchEvent(projectCreatedEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch project created event
+		 * */
+		public function dispatchProjectCreatedEvent(project:IProject):void {
+			var projectCreatedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECT_CREATED, false, false, project, null, null);
+			
+			if (hasEventListener(RadiateEvent.PROJECT_CREATED)) {
+				dispatchEvent(projectCreatedEvent);
+			}
+		}
+		
+		/**
+		 * Dispatch a history change event
+		 * */
+		public function dispatchHistoryChangeEvent(newIndex:int, oldIndex:int):void {
+			var event:RadiateEvent = new RadiateEvent(RadiateEvent.HISTORY_CHANGE);
+			
+			if (hasEventListener(RadiateEvent.HISTORY_CHANGE)) {
+				event.newIndex = newIndex;
+				event.oldIndex = oldIndex;
+				event.historyEventItem = getHistoryItemAtIndex(newIndex);
+				dispatchEvent(event);
+			}
+		}
+		
+		/**
+		 * Sets the logging target
+		 * */
+		public static function setLoggingTarget(target:AbstractTarget = null, category:String = null, consoleObject:Object = null):void {
+			
+			// Log only messages for the classes in the mx.rpc.* and 
+			// mx.messaging packages.
+			//logTarget.filters=["mx.rpc.*","mx.messaging.*"];
+			//var filters:Array = ["mx.rpc.*", "mx.messaging.*"];
+			//var filters:Array = ["mx.rpc.*", "mx.messaging.*"];
+			
+			// Begin logging.
+			if (target) {
+				logTarget = target;
+				//logTarget.filters = filters;
+				logTarget.level = LogEventLevel.ALL;
+				Log.addTarget(target);
+			}
+			
+			// set reference to logger
+			if (category) {
+				log = Log.getLogger(category);
+			}
+			else {
+				log = Log.getLogger(RADIATE_LOG);
+			}
+			
+			if (consoleObject) {
+				console = consoleObject;
+			}
+			
+		}
+		
+		/**
+		 * Creates the list of components and tools.
+		 * */
+		public static function initialize():void {
+			var componentsXML:XML 	= new XML(new Radii8LibrarySparkAssets.sparkManifestDefaults());
+			var toolsXML:XML 		= new XML(new Radii8LibraryToolAssets.toolsManifestDefaults());
+			var inspectorsXML:XML 	= new XML(new Radii8LibraryInspectorAssets.inspectorsManifestDefaults());
+			var devicesXML:XML		= new XML(new Radii8LibraryDeviceAssets.devicesManifestDefaults());
+			
+			createSettingsData();
+
+			createSavedData();
+			
+			createComponentList(componentsXML);
+			
+			createInspectorsList(inspectorsXML);
+			
+			createToolsList(toolsXML);
+			
+			createDevicesList(devicesXML);
+		}
+		
+		/**
+		 * Startup 
+		 * */
+		public static function startup():void {
+			
+			//ExternalInterface.call("Radiate.getInstance");
+			ExternalInterface.call("Radiate.instance.setFlashInstance", ExternalInterface.objectID);
+			
+			//instance.getLoggedInStatus();
+		}
+		
+		/**
+		 * Creates the list of components.
+		 * */
+		public static function createComponentList(xml:XML):void {
+			var length:uint;
+			var items:XMLList;
+			var className:String;
+			var skinClassName:String;
+			var inspectors:Array;
+			var hasDefinition:Boolean;
+			var classType:Object;
+			var includeItem:Boolean;
+			var attributes:XMLList;
+			var attributesLength:int;
+			var defaults:Object;
+			var propertyName:String;
+			var item:XML;
+			
+			
+			// get list of component classes 
+			items = XML(xml).component;
+			
+			length = items.length();
+			
+			for (var i:int;i<length;i++) {
+				item = items[i];
+				
+				var name:String = String(item.id);
+				className = item.attribute("class");
+				skinClassName = item.attribute("skinClass");
+				//inspectors = item.inspector;
+				
+				includeItem = item.attribute("include")=="false" ? false : true;
+				
+				
+				
+				// check that definitions exist in domain
+				// skip any support classes
+				if (className.indexOf("mediaClasses")==-1 && 
+					className.indexOf("gridClasses")==-1 &&
+					className.indexOf("windowClasses")==-1 &&
+					className.indexOf("supportClasses")==-1) {
+					
+					hasDefinition = ApplicationDomain.currentDomain.hasDefinition(className);
+					
+					if (hasDefinition) {
+						classType = ApplicationDomain.currentDomain.getDefinition(className);
+						
+						// need to check if we have the skin as well
+						
+						//hasDefinition = ApplicationDomain.currentDomain.hasDefinition(skinClassName);
+						
+						if (hasDefinition) {
+							
+							// get default values
+							if (item.defaults) {
+								attributes = item.defaults.attributes();
+								attributesLength = attributes.length();
+								defaults = {};
+								
+								for each (var value:Object in attributes) {
+									propertyName = String(value.name());
+									
+									if (propertyName=="dataProvider") {
+										var array:Array = String(value).split(",");
+										defaults[propertyName] = new ArrayCollection(array);
+									}
+									else {
+										defaults[propertyName] = String(value);
+									}
+								}
+							}
+							
+							addComponentType(item.@id, className, classType, inspectors, null, defaults, null, includeItem);
+						}
+						else {
+							log.error("Component skin class, '" + skinClassName + "' not found for '" + className + "'.");
+						}
+					}
+					else {
+						log.error("Component class not found: " + className);
+					}
+					
+				}
+				else {
+					// delete support classes
+					// may need to refactor why we are including them in the first place
+					delete items[i];
+					length--;
+				}
+			}
+			
+			// componentDescriptions should now be populated
+		}
+		
+		/**
+		 * Creates the list of inspectors.
+		 * */
+		public static function createInspectorsList(xml:XML):void {
+			var length:uint;
+			var inspectorsLength:uint;
+			var items:XMLList;
+			var className:String;
+			var skinClassName:String;
+			var inspectorClassName:String;
+			var hasDefinition:Boolean;
+			var classType:Object;
+			var includeItem:Boolean;
+			var attributes:XMLList;
+			var attributesLength:int;
+			var defaults:Object;
+			var propertyName:String;
+			var item:XML;
+			var inspectorItems:XMLList;
+			var inspector:XML;
+			var inspectableClass:InspectableClass;
+			var inspectorData:InspectorData;
+			
+			
+			// get list of inspector classes 
+			items = XML(xml).item;
+			
+			length = items.length();
+			
+			// add inspectable classes to the dictionary
+			for (var i:int;i<length;i++) {
+				inspectableClass = new InspectableClass(items[i]);
+				className = inspectableClass.className;
+				
+				if (inspectableClassesDictionary[className]==null) {
+					inspectableClassesDictionary[className] = inspectableClass;
+				}
+				else {
+					log.warn("Inspectable class, '" + className + "', was listed more than once during import.");
+				}
+					
+			}
+			
+			// check that definitions exist in domain
+			for each (inspectableClass in inspectableClassesDictionary) {
+			
+				length = inspectableClass.inspectors.length;
+				j = 0;
+				
+				for (var j:int;j<length;j++) {
+					inspectorData = inspectableClass.inspectors[j];
+					className = inspectorData.className;
+					
+					if (inspectorsDictionary[className]==null) {
+						
+						hasDefinition = ApplicationDomain.currentDomain.hasDefinition(className);
+						
+						if (hasDefinition) {
+							classType = ApplicationDomain.currentDomain.getDefinition(className);
+						}
+						else {
+							log.error("Inspector class not found: " + className);
+						}
+						
+						// not passing in classType now since we may load it in later dynamically
+						addInspectorType(inspectorData.name, className, null, inspectorData.icon, defaults);
+					}
+					else {
+						//log.warn("Inspector class: " + className + ", is already in the dictionary");
+					}
+				}
+			}
+			
+			// inspectorsInstancesDictionary should now be populated
+		}
+		
+		
+		/**
+		 * Creates the list of tools.
+		 * */
+		public static function createToolsList(xml:XML):void {
+			var inspectorClassName:String;
+			var hasDefinition:Boolean;
+			var toolClassDefinition:Object;
+			var inspectorClassDefinition:Object;
+			var inspectorClassFactory:ClassFactory;
+			var toolClassFactory:ClassFactory;
+			var items:XMLList;
+			var className:String;
+			var includeItem:Boolean;
+			var attributes:XMLList;
+			var length:uint;
+			var attributesLength:int;
+			var defaults:Object;
+			var propertyName:String;
+			var toolInstance:ITool;
+			var inspectorInstance:UIComponent;
+			var name:String;
+			var cursorItems:XMLList;
+			var cursorItem:XML;
+			var cursorName:String;
+			var cursors:Dictionary;
+			var cursorsCount:int;
+			var cursorData:MouseCursorData;
+			var cursorBitmapDatas:Vector.<BitmapData>;
+			var cursorBitmap:Bitmap;
+			var cursorClass:Class;
+			var cursorID:String;
+			var cursorX:int;
+			var cursorY:int;
+			var item:XML;
+			
+			// get list of tool classes 
+			items = XML(xml).tool;
+			
+			length = items.length();
+			
+			for (var i:int;i<length;i++) {
+				item = items[i];
+				
+				name = String(item.id);
+				className = item.attribute("class");
+				inspectorClassName = item.attribute("inspector");
+				cursorItems = item..cursor;
+				
+				includeItem = item.attribute("include")=="false" ? false : true;
+				
+				if (!includeItem) continue;
+				
+				hasDefinition = ApplicationDomain.currentDomain.hasDefinition(className);
+				
+				if (hasDefinition) {
+					toolClassDefinition = ApplicationDomain.currentDomain.getDefinition(className);
+					
+					
+					// get default values
+					if (item.defaults) {
+						attributes = item.defaults.attributes();
+						attributesLength = attributes.length();
+						defaults = {};
+						
+						for each (var value:Object in attributes) {
+							propertyName = String(value.name());
+							
+							if (propertyName=="dataProvider") {
+								defaults[propertyName] = new ArrayCollection(String(value).split(","));
+							}
+							else {
+								defaults[propertyName] = String(value);
+							}
+						}
+					}
+					
+					// create tool
+					toolClassFactory = new ClassFactory(toolClassDefinition as Class);
+					toolClassFactory.properties = defaults;
+					toolInstance = toolClassFactory.newInstance();
+					
+					
+					// create inspector
+					if (inspectorClassName!="") {
+						hasDefinition = ApplicationDomain.currentDomain.hasDefinition(inspectorClassName);
+						
+						if (hasDefinition) {
+							inspectorClassDefinition = ApplicationDomain.currentDomain.getDefinition(inspectorClassName);
+							
+							// Create tool inspector
+							inspectorClassFactory = new ClassFactory(inspectorClassDefinition as Class);
+							//classFactory.properties = defaults;
+							inspectorInstance = inspectorClassFactory.newInstance();
+					
+						}
+						else {
+							var errorMessage:String = "Could not find inspector, '" + inspectorClassName + "' for tool, '" + className + "'. ";
+							errorMessage += "You may need to add a reference to it in RadiateReferences.";
+							log.error(errorMessage);
+						}
+					}
+					
+					
+					cursorsCount = cursorItems.length();
+					
+					if (cursorsCount>0) {
+						cursors = new Dictionary(false);
+					}
+
+					// create mouse cursors
+					for (var j:int=0;j<cursorsCount;j++) {
+						cursorItem = cursorItems[j];
+						cursorName = cursorItem.@name.toString();
+						cursorX = int(cursorItem.@x.toString());
+						cursorY = int(cursorItem.@y.toString());
+						cursorID = cursorName != "" ? className + "." + cursorName : className;
+			
+						// Create a MouseCursorData object 
+						cursorData = new MouseCursorData();
+						
+						// Specify the hotspot 
+						cursorData.hotSpot = new Point(cursorX, cursorY); 
+						
+						// Pass the cursor bitmap to a BitmapData Vector 
+						cursorBitmapDatas = new Vector.<BitmapData>(1, true); 
+						
+						// Create the bitmap cursor 
+						// The bitmap must be 32x32 pixels or smaller, due to an OS limitation
+						//CursorClass = Radii8LibraryToolAssets.EyeDropper;
+						
+						if (cursorName) {
+							cursorClass = toolClassDefinition[cursorName];
+						}
+						else {
+							cursorClass = toolClassDefinition["Cursor"];
+						}
+						
+						cursorBitmap = new cursorClass();
+						
+						// Pass the value to the bitmapDatas vector 
+						cursorBitmapDatas[0] = cursorBitmap.bitmapData;
+						
+						// Assign the bitmap to the MouseCursor object 
+						cursorData.data = cursorBitmapDatas;
+						
+						// Register the MouseCursorData to the Mouse object with an alias 
+						Mouse.registerCursor(cursorID, cursorData);
+						
+						cursors[cursorName] = {cursorData:cursorData, id:cursorID};
+					}
+					
+					if (cursorsCount>0) {
+						mouseCursors[className] = cursors;
+					}
+					
+					//trace("tool cursors:", cursors);
+					var toolDescription:ComponentDescription = addToolType(item.@id, className, toolClassDefinition, toolInstance, inspectorClassName, null, defaults, null, cursors);
+					//trace("tool cursors:", toolDescription.cursors);
+				}
+				else {
+					//trace("Tool class not found: " + classDefinition);
+					log.error("Tool class not found: " + toolClassDefinition);
+				}
+				
+			}
+			
+			// toolDescriptions should now be populated
+		}
+		
+		/**
+		 * Creates the list of devices.
+		 * */
+		public static function createDevicesList(xml:XML):void {
+			var includeItem:Boolean;
+			var items:XMLList;
+			var length:uint;
+			var name:String;
+			var item:XML;
+			var device:Device;
+			var type:String;
+			
+			const RES_WIDTH:String = "resolutionWidth";
+			const RES_HEIGHT:String = "resolutionHeight";
+			const USABLE_WIDTH_PORTRAIT:String = "usableWidthPortrait";
+			const USABLE_HEIGHT_PORTRAIT:String = "usableHeightPortrait";
+			const USABLE_WIDTH_LANDSCAPE:String = "usableWidthLandscape";
+			const USABLE_HEIGHT_LANDSCAPE:String = "usableHeightLandscape";
+			
+			
+			// get list of device classes 
+			items = XML(xml).size;
+			
+			length = items.length();
+			
+			for (var i:int;i<length;i++) {
+				item = items[i];
+				
+				name = item.attribute("name");
+				type = item.attribute("type");
+				
+				device = new Device();
+				device.name = name;
+				device.type = type;
+				
+				if (type=="device") {
+					device.ppi 					= item.attribute("ppi");
+					
+					device.resolutionWidth 		= item.attribute(RES_WIDTH);
+					device.resolutionHeight 	= item.attribute(RES_HEIGHT);
+					device.usableWidthPortrait 	= item.attribute(USABLE_WIDTH_PORTRAIT);
+					device.usableHeightPortrait = item.attribute(USABLE_HEIGHT_PORTRAIT);
+					device.usableWidthLandscape = item.attribute(USABLE_WIDTH_LANDSCAPE);
+					device.usableHeightLandscape = item.attribute(USABLE_HEIGHT_LANDSCAPE);
+				}
+				else if (type=="screen") {
+					device.ppi 					= item.attribute("ppi");
+					device.resolutionWidth 		= item.attribute(RES_WIDTH);
+					device.resolutionHeight 	= item.attribute(RES_HEIGHT);
+					continue;
+				}
+				
+				includeItem = item.attribute("include")=="false" ? false : true;
+				
+				deviceCollections.addItem(device);
+				
+			}
+			
+			// deviceDescriptions should now be populated
+		}
+		
+		/**
+		 * Helper method to get the ID of the mouse cursor by name.
+		 * 
+		 * */
+		public function getMouseCursorID(tool:ITool, name:String = "Cursor"):String {
+			var component:ComponentDescription = getToolDescription(tool);
+			
+			
+			if (component.cursors && component.cursors[name]) {
+				return component.cursors[name].id;
+			}
+			
+			return null;
+		}
+		
+		//----------------------------------
+		//  target
+		//----------------------------------
+		
+		/**
+		 * Use setTarget() or setTargets() method to set the target. 
+		 * */
+		public function get target():Object {
+			if (_targets.length > 0)
+				return _targets[0];
+			else
+				return null;
+		}
+		
+		/**
+		 *  @private
+		 */
+		/*[Bindable]
+		public function set target(value:Object):void {
+			if (_targets.length == 1 && target==value) return;
+			
+			_targets.splice(0);
+			
+			if (value) {
+				_targets[0] = value;
+			}
+		}*/
+
+		
+		//----------------------------------
+		//  targets
+		//----------------------------------
+		
+		/**
+		 *  @private
+		 *  Storage for the targets property.
+		 */
+		private var _targets:Array = [];
+		
+		/**
+		 * Selected targets
+		 * */
+		public function get targets():Array {
+			return _targets;
+		}
+		
+		/**
+		 * Use setTargets() to set the targets
+		 *  @private
+		 * */
+		/*public function set targets(value:Array):void {
+			// remove listeners from previous targets
+			var n:int = _targets.length;
+			
+			for (var i:int = n - 1; i >= 0; i--) {
+				if (_targets[i] == null) {
+					continue;
+				}
+				
+				//removeHandlers(_targets[i]);
+			}
+			
+			// Strip out null values.
+			// Binding will trigger again when the null targets are created.
+			n = value.length;
+			
+			for (i = n - 1; i >= 0; i--) {
+				if (value[i] == null) {
+					value.splice(i,1);
+					continue;
+				}
+				
+				//addHandlers(value[i]);
+			}
+			
+			_targets = value;
+			
+		}*/
+		
+		//----------------------------------
+		//  project
+		//----------------------------------
+		
+		private var _selectedProject:IProject;
+		
+		/**
+		 * Reference to the current project
+		 * */
+		public function get selectedProject():IProject {
+			return _selectedProject;
+		}
+		
+		/**
+		 *  @private
+		 */
+		[Bindable(event="projectChange")]
+		public function set selectedProject(value:IProject):void {
+			if (value==_selectedProject) return;
+			_selectedProject = value;
+			
+		}
+		
+		//----------------------------------
+		//  document
+		//----------------------------------
+		
+		private var _documentsTabNavigator:TabNavigator;
+
+		/**
+		 * Reference to the tab navigator that creates documents
+		 * */
+		public function get documentsTabNavigator():TabNavigator {
+			return _documentsTabNavigator;
+		}
+
+		/**
+		 * @private
+		 */
+		public function set documentsTabNavigator(value:TabNavigator):void {
+			_documentsTabNavigator = value;
+		}
+
+		
+		/**
+		 * Reference to the tab that the document belongs to
+		 * */
+		public var documentsContainerDictionary:Dictionary = new Dictionary(true);
+		
+		/**
+		 * Reference to the tab that the document preview belongs to
+		 * */
+		public var documentsPreviewDictionary:Dictionary = new Dictionary(true);
+		
+		private var _selectedDocument:IDocument;
+		
+		/**
+		 * Get the current document.
+		 * */
+		public function get selectedDocument():IDocument {
+			return _selectedDocument;
+		}
+		
+		/**
+		 *  @private
+		 */
+		[Bindable(event="documentChange")]
+		public function set selectedDocument(value:IDocument):void {
+			if (value==_selectedDocument) return;
+			_selectedDocument = value;
+		}
+		
+		/**
+		 * Templates for creating new projects or documents
+		 * */
+		[Bindable]
+		public var templates:Array;
+		
+		//----------------------------------
+		//  documents
+		//----------------------------------
+		
+		/**
+		 *  @private
+		 *  Storage for the documents property.
+		 */
+		private var _documents:Array = [];
+		
+		/**
+		 * Selected documents
+		 * */
+		public function get documents():Array {
+			return _documents;
+		}
+		
+		/**
+		 * Selected documents
+		 *  @private
+		 * */
+		[Bindable]
+		public function set documents(value:Array):void {
+			// the following comments are old possibly irrelevant...
+			// remove listeners from previous documents
+			var n:int = _documents.length;
+			
+			for (var i:int = n - 1; i >= 0; i--) {
+				if (_documents[i] == null) {
+					continue;
+				}
+				
+				//removeHandlers(_documents[i]);
+			}
+			
+			// Strip out null values.
+			// Binding will trigger again when the null documents are created.
+			n = value.length;
+			
+			for (i = n - 1; i >= 0; i--) {
+				if (value[i] == null) {
+					value.splice(i,1);
+					continue;
+				}
+				
+				//addHandlers(value[i]);
+			}
+			
+			_documents = value;
+			
+		}
+		
+		
+		//----------------------------------
+		//  projects
+		//----------------------------------
+		
+		
+		/**
+		 * Reference to the projects belongs to
+		 * */
+		public var projectsDictionary:Dictionary = new Dictionary(true);
+		
+		/**
+		 *  @private
+		 *  Storage for the projects property.
+		 */
+		private var _projects:Array = [];
+		
+		/**
+		 * Selected projects
+		 * */
+		public function get projects():Array {
+			return _projects;
+		}
+		
+		/**
+		 * Selected projects
+		 *  @private
+		 * */
+		[Bindable]
+		public function set projects(value:Array):void {
+			_projects = value;
+			
+		}
+		
+		private var _attachments:Array = [];
+
+		/**
+		 * Attachments
+		 * */
+		[Bindable]
+		public function get attachments():Array {
+			return _attachments;
+		}
+
+		public function set attachments(value:Array):void {
+			_attachments = value;
+		}
+		
+		private var _assets:ArrayCollection = new ArrayCollection();
+
+		/**
+		 * Assets
+		 * */
+		[Bindable]
+		public function get assets():ArrayCollection {
+			return _assets;
+		}
+
+		public function set assets(value:ArrayCollection):void {
+			_assets = value;
+		}
+
+		
+		private var _toolLayer:IVisualElementContainer;
+
+		/**
+		 * Container that tools can draw too
+		 * */
+		public function get toolLayer():IVisualElementContainer {
+			return _toolLayer;
+		}
+
+		/**
+		 * @private
+		 */
+		public function set toolLayer(value:IVisualElementContainer):void {
+			_toolLayer = value;
+		}
+
+		
+		/**
+		 * Default log target
+		 * */
+		public static var defaultLogTarget:AbstractTarget = new RadiateLogTarget();
+		
+		/**
+		 * Attempt to support a console
+		 * */
+		public static var logTarget:AbstractTarget;
+		
+		private static var _log:ILogger;
+		
+		private static var _console:Object;
+		
+		public static var SETTINGS_DATA_NAME:String = "settingsData";
+		public static var SAVED_DATA_NAME:String 	= "savedData";
+		public static var WP_HOST:String = "http://www.radii8.com";
+		public static var WP_PATH:String = "/r8m/";
+		public static var WP_USER_PATH:String = "";
+		public static var DEFAULT_DOCUMENT_WIDTH:int = 800;
+		public static var DEFAULT_DOCUMENT_HEIGHT:int = 792;
+		
+		public static function getWPURL():String {
+			return WP_HOST + WP_PATH + WP_USER_PATH;
+		}
+		
+		/**
+		 * Is true when preview is visible. This is manually set. 
+		 * Needs refactoring. 
+		 * */
+		public var isPreviewVisible:Boolean;
+		
+		/**
+		 * Settings 
+		 * */
+		public static var settings:Settings;
+		
+		/**
+		 * Settings 
+		 * */
+		public static var savedData:SavedData;
+		
+		/**
+		 * Collection of mouse cursors that can be added or removed to 
+		 * */
+		[Bindable]
+		public static var mouseCursors:Dictionary = new Dictionary(true);
+		
+		//----------------------------------
+		//
+		//  Device Management
+		// 
+		//----------------------------------
+		
+		/**
+		 * Collection of devices
+		 * */
+		[Bindable]
+		public static var deviceCollections:ArrayCollection = new ArrayCollection();
+		
+		
+		//----------------------------------
+		//
+		//  Tools Management
+		// 
+		//----------------------------------
+		
+		public var _selectedTool:ITool;
+		
+		/**
+		 * Get selected tool.
+		 * */
+		public function get selectedTool():ITool {
+			return _selectedTool;
+		}
+		
+		/**
+		 * Collection of tools that can be added or removed to 
+		 * */
+		[Bindable]
+		public static var toolsDescriptions:ArrayCollection = new ArrayCollection();
+		
+		/**
+		 * Add the named tool class to the list of available tools.
+		 * 
+		 * Not sure if we should create an instance here or earlier or later. 
+		 * */
+		public static function addToolType(name:String, className:String, classType:Object, instance:ITool, inspectorClassName:String, icon:Object = null, defaultProperties:Object=null, defaultStyles:Object=null, cursors:Dictionary = null):ComponentDescription {
+			var definition:ComponentDescription;
+			var length:uint = toolsDescriptions.length;
+			var item:ComponentDescription;
+			
+			for (var i:uint;i<length;i++) {
+				item = toolsDescriptions.getItemAt(i) as ComponentDescription;
+				
+				// check if it exists already
+				if (item && item.classType==classType) {
+					return item;
+					//return false;
+				}
+			}
+			
+			definition = new ComponentDescription();
+			
+			definition.name = name;
+			definition.icon = icon;
+			definition.className = className;
+			definition.classType = classType;
+			definition.defaultStyles = defaultStyles;
+			definition.defaultProperties = defaultProperties;
+			definition.instance = instance;
+			definition.inspectorClassName = inspectorClassName;
+			definition.cursors = cursors;
+			
+			toolsDescriptions.addItem(definition);
+			
+			return definition;
+		}
+		
+		/**
+		 * Sets the selected tool
+		 * */
+		public function setTool(value:ITool, dispatchEvent:Boolean = true, cause:String = ""):void {
+			
+			if (selectedTool) {
+				selectedTool.disable();
+			}
+			
+			_selectedTool = value;
+			
+			if (selectedTool) {
+				selectedTool.enable();
+			}
+			
+			if (dispatchEvent) {
+				instance.dispatchToolChangeEvent(selectedTool);
+			}
+			
+		}
+		
+		/**
+		 * Get tool description.
+		 * */
+		public function getToolDescription(instance:ITool):ComponentDescription {
+			var length:int = toolsDescriptions.length;
+			var componentDescription:ComponentDescription;
+			
+			for (var i:int;i<length;i++) {
+				componentDescription = ComponentDescription(toolsDescriptions.getItemAt(i));
+				
+				if (componentDescription.instance==instance) {
+					return componentDescription;
+				}
+			}
+			
+			return null;
+		}
+		
+		/**
+		 * Get tool by name.
+		 * */
+		public function getToolByName(name:String):ComponentDescription {
+			var length:int = toolsDescriptions.length;
+			var componentDescription:ComponentDescription;
+			
+			for (var i:int;i<length;i++) {
+				componentDescription = ComponentDescription(toolsDescriptions.getItemAt(i));
+				
+				if (componentDescription.className==name) {
+					return componentDescription;
+				}
+			}
+			
+			return null;
+		}
+		
+		/**
+		 * Get tool by type.
+		 * */
+		public function getToolByType(type:Class):ComponentDescription {
+			var length:int = toolsDescriptions.length;
+			var componentDescription:ComponentDescription;
+			
+			for (var i:int;i<length;i++) {
+				componentDescription = ComponentDescription(toolsDescriptions.getItemAt(i));
+				
+				if (componentDescription.classType==type) {
+					return componentDescription;
+				}
+			}
+			
+			return null;
+		}
+		
+		//----------------------------------
+		//
+		//  Inspector Management
+		// 
+		//----------------------------------
+		
+		/**
+		 * Collection of inspectors that can be added or removed to 
+		 * */
+		[Bindable]
+		public static var inspectorsDescriptions:ArrayCollection = new ArrayCollection();
+		
+		/**
+		 * Dictionary of classes that have inspectors
+		 * */
+		[Bindable]
+		public static var inspectableClassesDictionary:Dictionary = new Dictionary();
+		
+		/**
+		 * Dictionary of instances of inspectors searched by class name
+		 * */
+		[Bindable]
+		public static var inspectorsDictionary:Dictionary = new Dictionary();
+		
+		/**
+		 * Add the named inspector class to the list of available inspectors
+		 * */
+		public static function addInspectorType(name:String, className:String, classType:Object, icon:Object = null, defaults:Object=null):Boolean {
+			var inspectorData:InspectorData;
+			
+			if (inspectorsDictionary[className]==null) {
+				inspectorData = new InspectorData();
+				inspectorData.name = name==null ? className : name;
+				inspectorData.className = className;
+				inspectorData.classType = classType;
+				inspectorData.icon = icon;
+				inspectorData.defaults = defaults;
+				inspectorsDictionary[className] = inspectorData;
+			}
+			
+			
+			return true;
+		}
+		
+		/**
+		 * Gets inspector classes or null if the definition is not found.
+		 * */
+		public function getInspectableClassData(className:String):InspectableClass {
+			var inspectableClass:InspectableClass = inspectableClassesDictionary[className];
+			
+			return inspectableClass;
+		}
+		
+		/**
+		 * Gets an instance of the inspector class or null if the definition is not found.
+		 * */
+		public function getInspectorInstance(className:String):IInspector {
+			var inspectorData:InspectorData = inspectorsDictionary[className];
+			
+			if (inspectorData) {
+				if (inspectorData.instance) {
+					return inspectorData.instance;
+				}
+				
+				var instance:IInspector = inspectorData.getInstance();
+				
+				return instance;
+			
+			}
+
+			return null;
+		}
+		
+		/**
+		 * Gets an instance of the inspector class or null if the definition is not found.
+		 * */
+		public function getInspector(target:Object, domain:ApplicationDomain = null):IInspector {
+			var className:String;
+			
+			if (target) {
+				className = ClassUtils.getQualifiedClassName(target);
+				
+				var instance:IInspector = getInspectorInstance(className);
+				
+				return instance;
+			}
+
+			return null;
+		}
+		
+		/**
+		 * Gets array of inspector data for the given fully qualified class or object
+		 * */
+		public function getInspectors(target:Object):Array {
+			var className:String;
+			var inspectors:Array;
+			var inspectorDataArray:Array;
+			var inspectableClass:InspectableClass;
+			var length:int;
+			
+			if (target==null) return [];
+			
+			if (target is Object) {
+				className = ClassUtils.getQualifiedClassName(target);
+				
+				if (target is Application) {
+					className = ClassUtils.getSuperClassName(target);
+				}
+			}
+			
+			if (target is String) {
+				className = String(target);
+			}
+			
+			className = className ? className.split("::").join(".") : className;
+			
+			inspectableClass = getInspectableClassData(className);
+			
+			if (inspectableClass) {
+				return inspectableClass.inspectors;
+			}
+
+			return [];
+		}
+		
+		//----------------------------------
+		//
+		//  Scale Management
+		// 
+		//----------------------------------
+		
+		/**
+		 * Stops on the scale
+		 * */
+		public var scaleStops:Array = [.05,.0625,.0833,.125,.1666,.25,.333,.50,.667,1,1.25,1.50,1.75,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];
+		
+		/**
+		 * Increases the zoom of the target application to next value 
+		 * */
+		public function increaseScale(valueFrom:Number = NaN, dispatchEvent:Boolean = true):void {
+			var newScale:Number;
+			var currentScale:Number;
+			
+		
+			if (isNaN(valueFrom)) {
+				currentScale = Number(DisplayObject(selectedDocument.instance).scaleX.toFixed(4));
+			}
+			else {
+				currentScale = valueFrom;
+			}
+			
+			//newScale = DisplayObject(document).scaleX;
+			
+			for (var i:int=0;i<scaleStops.length;i++) {
+				if (currentScale<scaleStops[i]) {
+					newScale = scaleStops[i];
+					break;
+				}
+			}
+			
+			if (i==scaleStops.length-1) {
+				newScale = scaleStops[i];
+			}
+			
+			newScale = Number(newScale.toFixed(4));
+			
+			setScale(newScale, dispatchEvent);
+				
+		}
+		
+		/**
+		 * Decreases the zoom of the target application to next value 
+		 * */
+		public function decreaseScale(valueFrom:Number = NaN, dispatchEvent:Boolean = true):void {
+			var newScale:Number;
+			var currentScale:Number;
+		
+			if (isNaN(valueFrom)) {
+				currentScale = Number(DisplayObject(selectedDocument.instance).scaleX.toFixed(4));
+			}
+			else {
+				currentScale = valueFrom;
+			}
+			
+			//newScale = DisplayObject(document).scaleX;
+			
+			for (var i:int=scaleStops.length;i--;) {
+				if (currentScale>scaleStops[i]) {
+					newScale = scaleStops[i];
+					break;
+				}
+			}
+			
+			if (i==0) {
+				newScale = scaleStops[i];
+			}
+			
+			newScale = Number(newScale.toFixed(4));
+			
+			setScale(newScale, dispatchEvent);
+				
+		}
+		
+		/**
+		 * Sets the zoom of the target application to value. 
+		 * */
+		public function setScale(value:Number, dispatchEvent:Boolean = true):void {
+			
+			if (selectedDocument && !isNaN(value) && value>0) {
+				//DisplayObject(selectedDocument.instance).scaleX = value;
+				//DisplayObject(selectedDocument.instance).scaleY = value;
+				selectedDocument.scale = value;
+				
+				if (dispatchEvent) {
+					dispatchScaleChangeEvent(selectedDocument, value, value);
+				}
+			}
+		}
+		
+		/**
+		 * Gets the scale of the target application. 
+		 * */
+		public function getScale():Number {
+			
+			if (selectedDocument && selectedDocument.instance && "scaleX" in selectedDocument.instance) {
+				return Math.max(selectedDocument.instance.scaleX, selectedDocument.instance.scaleY);
+			}
+			
+			return NaN;
+		}
+		
+		/**
+		 * Center the application
+		 * */
+		public function centerApplication(vertically:Boolean = true, verticallyTop:Boolean = true, totalDocumentPadding:int = 0):void {
+			if (!canvasScroller) return;
+			var viewport:IViewport = canvasScroller.viewport;
+			var documentVisualElement:IVisualElement = IVisualElement(selectedDocument.instance);
+			//var contentHeight:int = viewport.contentHeight * getScale();
+			//var contentWidth:int = viewport.contentWidth * getScale();
+			// get document size NOT scroll content size
+			var contentHeight:int = documentVisualElement.height * getScale();
+			var contentWidth:int = documentVisualElement.width * getScale();
+			var newHorizontalPosition:int;
+			var newVerticalPosition:int;
+			var needsValidating:Boolean;
+			var vsbWidth:int = canvasScroller.verticalScrollBar ? canvasScroller.verticalScrollBar.width : 11;
+			var hsbHeight:int = canvasScroller.horizontalScrollBar ? canvasScroller.horizontalScrollBar.height : 11;
+			var availableWidth:int = canvasScroller.width;// - vsbWidth;
+			var availableHeight:int = canvasScroller.height;// - hsbHeight;
+			
+			if (LayoutManager.getInstance().isInvalid()) {
+				needsValidating = true;
+				//LayoutManager.getInstance().validateClient(canvasScroller as ILayoutManagerClient);
+				//LayoutManager.getInstance().validateNow();
+			}
+			
+			
+			if (vertically) {
+				// scroller height 359, content height 504, content height validated 550
+				// if document is taller than available space and 
+				// verticalTop is true then keep it at the top
+				if (contentHeight > availableHeight && verticallyTop) {
+					newVerticalPosition = canvasBackground.y - totalDocumentPadding;
+					viewport.verticalScrollPosition = Math.max(0, newVerticalPosition);
+				}
+				else if (contentHeight > availableHeight) {
+					newVerticalPosition = (contentHeight + hsbHeight - availableHeight) / 2;
+					viewport.verticalScrollPosition = Math.max(0, newVerticalPosition);
+				}
+				else {
+					// content height 384, scroller height 359, vsp 12
+					newVerticalPosition = (availableHeight + hsbHeight - contentHeight) / 2;
+					viewport.verticalScrollPosition = Math.max(0, newVerticalPosition);
+				}
+			}
+			
+			// if width of content is wider than canvasScroller width then center
+			if (canvasScroller.width < contentWidth) {
+				newHorizontalPosition = (contentWidth - availableWidth) / 2;
+				viewport.horizontalScrollPosition = Math.max(0, newHorizontalPosition);
+			}
+			else {
+				//newHorizontalPosition = (contentWidth - canvasScroller.width) / 2;
+				//viewport.horizontalScrollPosition = Math.max(0, newHorizontalPosition);
+			}
+		}
+		
+		/**
+		 * Restores the scale of the target application to 100%.
+		 * */
+		public function restoreDefaultScale(dispatchEvent:Boolean = true):void {
+			if (selectedDocument) {
+				setScale(1, dispatchEvent);
+			}
+		}
+		
+		/**
+		 * Sets the scale to fit the available space. 
+		 * */
+		public function scaleToFit(dispatchEvent:Boolean = true):void {
+			var width:int;
+			var height:int;
+			var availableWidth:int;
+			var availableHeight:int;
+			var widthScale:Number;
+			var heightScale:Number;
+			var newScale:Number;
+			var documentVisualElement:IVisualElement = selectedDocument ? selectedDocument.instance as IVisualElement : null;
+			
+			if (documentVisualElement) {
+			
+				//width = DisplayObject(document).width;
+				//height = DisplayObject(document).height;
+				width = documentVisualElement.width;
+				height = documentVisualElement.height;
+				var vsbWidth:int = canvasScroller.verticalScrollBar ? canvasScroller.verticalScrollBar.width : 20;
+				var hsbHeight:int = canvasScroller.horizontalScrollBar ? canvasScroller.horizontalScrollBar.height : 20;
+				availableWidth = canvasScroller.width - vsbWidth*2.5;
+				availableHeight = canvasScroller.height - hsbHeight*2.5;
+				
+				//var scrollerPaddedWidth:int = canvasScroller.width + documentPadding;
+				//var scrollerPaddedHeight:int = canvasScroller.height + documentPadding;
+			
+                // if the visible area is less than our content then scale down
+                if (height > availableHeight || width > availableWidth) {
+					heightScale = availableHeight/height;
+					widthScale = availableWidth/width;
+					newScale = Math.min(widthScale, heightScale);
+					width = newScale * width;
+					height = newScale * height;
+                }
+				else if (height < availableHeight && width < availableWidth) {
+					newScale = Math.min(availableHeight/height, availableWidth/width);
+					width = newScale * width;
+					height = newScale * height;
+					//newScale = Math.min(availableHeight/height, availableWidth/width);
+					//newScale = Math.max(availableHeight/height, availableWidth/width);
+                }
+
+				setScale(newScale, dispatchEvent);
+				
+				////////////////////////////////////////////////////////////////////////////////
+				/*var documentRatio:Number = width / height;
+				var canvasRatio:Number = availableWidth / availableHeight;
+				
+				var newRatio:Number = documentRatio / canvasRatio;
+				newRatio = canvasRatio / documentRatio;
+				newRatio = 1-documentRatio / canvasRatio;*/
+					
+			}
+		}
+		
+		//----------------------------------
+		//
+		//  Documentation Utility
+		// 
+		//----------------------------------
+		
+		public static var docsURL:String = "http://flex.apache.org/asdoc/";
+		public static var docsURL2:String = "http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/";
+		
+		/**
+		 * Returns the URL to the help document online based on MetaData passed to it. 
+		 * */
+		public static function getURLToHelp(metadata:MetaData, useBackupURL:Boolean = true):String {
+			var path:String = "";
+			var currentClass:String;
+			var sameClass:Boolean;
+			var prefix:String = "";
+			var url:String;
+			var packageName:String;
+			var declaredBy:String;
+			var backupURLNeeded:Boolean;
+			
+			if (metadata && metadata.declaredBy) {
+				declaredBy = metadata.declaredBy;
+				currentClass = declaredBy.replace(/::|\./g, "/");
+				
+				if (declaredBy.indexOf(".")!=-1) {
+					packageName = declaredBy.split(".")[0];
+					if (packageName=="flash") {
+						backupURLNeeded = true;
+					}
+				}
+				
+				if (metadata is StyleMetaData) {
+					prefix = "style:";
+				}
+				else if (metadata is EventMetaData) {
+					prefix = "event:";
+				}
+				
+				
+				path = currentClass + ".html#" + prefix + metadata.name;
+			}
+			
+			if (useBackupURL && backupURLNeeded) {
+				url  = docsURL2 + path;
+			}
+			else {
+				url  = docsURL + path;
+			}
+			
+			return url;
+		}
+		
+		//----------------------------------
+		//
+		//  Component Management
+		// 
+		//----------------------------------
+		
+		/**
+		 * Collection of visual elements that can be added or removed to 
+		 * */
+		[Bindable]
+		public static var componentDefinitions:ArrayCollection = new ArrayCollection();
+		
+		/**
+		 * Cache for component icons
+		 * */
+		[Bindable]
+		public static var contentCache:ContentCache = new ContentCache();
+		
+		/**
+		 * Add the named component class to the list of available components
+		 * */
+		public static function addComponentType(name:String, className:String, classType:Object, inspectors:Array = null, icon:Object = null, defaultProperties:Object=null, defaultStyles:Object=null, enabled:Boolean = true):Boolean {
+			var definition:ComponentDefinition;
+			var length:uint = componentDefinitions.length;
+			var item:ComponentDefinition;
+			
+			
+			for (var i:uint;i<length;i++) {
+				item = ComponentDefinition(componentDefinitions.getItemAt(i));
+				
+				// check if it exists already
+				if (item && item.classType==classType) {
+					return false;
+				}
+			}
+			
+			
+			definition = new ComponentDefinition();
+			
+			definition.name = name;
+			definition.icon = icon;
+			definition.className = className;
+			definition.classType = classType;
+			definition.defaultStyles = defaultStyles;
+			definition.defaultProperties = defaultProperties;
+			definition.inspectors = inspectors;
+			definition.enabled = enabled;
+			
+			componentDefinitions.addItem(definition);
+			
+			return true;
+		}
+		
+		/**
+		 * Remove the named component class
+		 * */
+		public static function removeComponentType(className:String):Boolean {
+			var definition:ComponentDefinition;
+			var length:uint = componentDefinitions.length;
+			var item:ComponentDefinition;
+			
+			for (var i:uint;i<length;i++) {
+				item = ComponentDefinition(componentDefinitions.getItemAt(i));
+				
+				if (item && item.classType==className) {
+					componentDefinitions.removeItemAt(i);
+				}
+			}
+			
+			return true;
+		}
+		
+		/**
+		 * Get the component by class name
+		 * */
+		public static function getComponentType(className:String, fullyQualified:Boolean = false):ComponentDefinition {
+			var definition:ComponentDefinition;
+			var length:uint = componentDefinitions.length;
+			var item:ComponentDefinition;
+			
+			for (v

<TRUNCATED>