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:49 UTC

[16/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/utils/HTMLDocumentExporter.as
----------------------------------------------------------------------
diff --git a/Radii8Library/src/com/flexcapacitor/utils/HTMLDocumentExporter.as b/Radii8Library/src/com/flexcapacitor/utils/HTMLDocumentExporter.as
new file mode 100644
index 0000000..c179e86
--- /dev/null
+++ b/Radii8Library/src/com/flexcapacitor/utils/HTMLDocumentExporter.as
@@ -0,0 +1,1370 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.utils {
+	import com.flexcapacitor.model.IDocument;
+	import com.flexcapacitor.utils.supportClasses.ComponentDescription;
+	import com.flexcapacitor.views.supportClasses.Styles;
+	
+	import flash.display.BitmapData;
+	import flash.display.DisplayObject;
+	import flash.display.JPEGEncoderOptions;
+	import flash.display.PNGEncoderOptions;
+	import flash.geom.Rectangle;
+	import flash.utils.ByteArray;
+	import flash.utils.Dictionary;
+	import flash.utils.getTimer;
+	
+	import mx.core.IUIComponent;
+	import mx.core.IVisualElement;
+	import mx.core.IVisualElementContainer;
+	import mx.graphics.codec.JPEGEncoder;
+	import mx.graphics.codec.PNGEncoder;
+	import mx.styles.IStyleClient;
+	import mx.utils.Base64Encoder;
+	
+	import spark.components.BorderContainer;
+	import spark.components.HGroup;
+	import spark.components.supportClasses.GroupBase;
+	import spark.layouts.BasicLayout;
+	import spark.layouts.HorizontalLayout;
+	import spark.layouts.TileLayout;
+	import spark.layouts.VerticalLayout;
+	import spark.utils.BitmapUtil;
+	
+	/**
+	 * Exports a document to HTML
+	 * */
+	public class HTMLDocumentExporter extends DocumentExporter {
+		
+		public function HTMLDocumentExporter() {
+		
+		}
+		
+		/**
+		 * Sets explicit size regardless if size is explicit
+		 * */
+		public var setExplicitSize:Boolean = true;
+		
+		/**
+		 * Sets styles inline
+		 * */
+		public var useInlineStyles:Boolean;
+		
+		/**
+		 * Name of token in the template that is replaced by the 
+		 * */
+		public var contentToken:String = "<!--template_content-->";
+		
+		/**
+		 * CSS to add to 
+		 * */
+		public var css:String;
+		
+		/**
+		 * Adds border box CSS 
+		 * */
+		public var borderBoxCSS:String;
+		
+		/**
+		 * Show outline 
+		 * */
+		public var showBordersCSS:String;
+		
+		/**
+		 * Zoom CSS
+		 * */
+		public var zoomCSS:String;
+		
+		/**
+		 * Page zoom level
+		 * */
+		public var scaleLevel:Number;
+		
+		/**
+		 * CSS for SVG button
+		 * */
+		public var buttonCSS:String;
+		
+		public var buttonCSS2:String;
+		
+		public var stylesheets:String;
+		
+		public var template:String;
+		
+		/**
+		 * Creates a snapshot of the application and sets it as the background image
+		 * */
+		public var showScreenshotBackground:Boolean = false;
+		
+		/**
+		 * Alpha of the background image
+		 * */
+		public var backgroundImageAlpha:Number = .5;
+		
+		/**
+		 * Used to create PNG images
+		 * */
+		public var pngEncoder:PNGEncoder;
+		
+		/**
+		 * Used to create JPEG images
+		 * */
+		public var jpegEncoder:JPEGEncoder;
+		
+		/**
+		 * Extension of the document when exporting to a file. 
+		 * */
+		public var extension:String;
+		
+		/**
+		 * Indicates when the user has typed in the text area
+		 * */
+		[Bindable]
+		public var isCodeModifiedByUser:Boolean;
+		
+		/**
+		 * Show borders around HTML elements
+		 * */
+		[Bindable]
+		public var showBorders:Boolean;
+		
+		/**
+		 * Use SVG button class
+		 * */
+		[Bindable]
+		public var useSVGButtonClass:Boolean = true;
+		
+		/**
+		 * Show full HTML page source
+		 * */
+		[Bindable]
+		public var showFullHTMLPageSource:Boolean = false;
+		
+		/**
+		 * Last source code
+		 * */
+		[Bindable]
+		public var sourceCode:String;
+		
+		public var includePreviewCode:Boolean;
+		
+		public var horizontalPositions:Array = ["x","left","right","horizontalCenter"];
+		public var horizontalCenterPosition:String = "horizontalCenter";
+		public var verticalPositions:Array = ["y","top","bottom","verticalCenter"];
+		public var verticalCenterPosition:String = "verticalCenter";
+		public var sizesPositions:Array = ["width","height"];
+		
+		public var addZoom:Boolean;
+		public var output:String = "";
+		public var cssOutput:String = "";
+		public var wrapInPreview:Boolean;
+		
+		/**
+		 * 
+		 * */
+		public var useWrapperDivs:Boolean;
+		public var showOnlyHTML:Boolean;
+		public var showOnlyCSS:Boolean;
+		
+		/**
+		 * @inheritDoc
+		 * */
+		public function export(iDocument:IDocument, reference:Boolean = false, target:Object = null):String {
+			var XML1:XML;
+			var application:Object = iDocument ? iDocument.instance : null;
+			var targetDescription:ComponentDescription;
+			var componentTree:ComponentDescription;
+			var zoomOutput:String;
+			var xml:XML;
+			
+			componentTree = iDocument.componentDescription;
+			cssOutput = "";
+			
+			// find target in display list and get it's code
+			targetDescription = DisplayObjectUtils.getTargetInComponentDisplayList(target, componentTree);
+			
+			
+			if (targetDescription) {
+				
+				// see the top of this document on how to generate source code
+				getAppliedPropertiesFromHistory(iDocument, targetDescription);
+			
+				if (!reference) {
+					//output = getHTMLOutputString(iDocument, iDocument.componentDescription);
+					
+					var includePreviewCode:Boolean = true;
+					var tabDepth:String = "";
+					
+					if (showFullHTMLPageSource) {
+						tabDepth = ""; //"\t\t\t";
+					}
+					
+					output = getHTMLOutputString(iDocument, targetDescription, true, tabDepth, includePreviewCode);
+					output += "\n";
+					
+					var applicationContainerID:String = "applicationContainer";
+					var zoomInID:String = wrapInPreview ? application.name : applicationContainerID;
+					
+					// not enabled at the moment - see code inspector
+					if (wrapInPreview) {
+						var wrapper:String = "<div id=\"" + applicationContainerID +"\" style=\"position:absolute;";
+						//output += "width:" + (component.instance.width + 40) + "px;";
+						wrapper += "width:100%;";
+						wrapper += "height:" + (targetDescription.instance.height + 40) + "px;";
+						wrapper += "background-color:#666666;\">\n" + output + "</div>";
+						output = wrapper;
+					}
+					
+					if (stylesheets) {
+						output += "\n" + stylesheets;
+					}
+					
+					var styles:String = "";
+					
+					if (showOnlyCSS) {
+						
+						// SPOT NUMBER 1
+						// you have to include css options in another spot as well below
+						// SEE SPOT NUMBER 2
+						// refactor
+						if (!useInlineStyles) {
+							styles = "\n" + cssOutput;
+						}
+						
+						if (css) {
+							styles += "\n" + css;
+						}
+						
+						if (useSVGButtonClass) {
+							styles += "\n" + buttonCSS2;
+						}
+						
+						if (showBorders) {
+							styles += "\n" + showBordersCSS;
+						}
+						
+						if (addZoom) {
+							//zoomOutput = zoomCSS.replace(/IFRAME_ID/g, "#" + application.name);
+							zoomOutput = zoomCSS.replace(/IFRAME_ID/g, "#" + zoomInID);
+							zoomOutput = zoomOutput.replace(/ZOOM_VALUE/g, iDocument.scale);
+							styles += "\n" + zoomOutput;
+						}
+						
+						output = styles;
+					}
+					else if (showOnlyHTML) {
+						
+						if (showFullHTMLPageSource) {
+							output = template.replace(contentToken, output);
+						}
+					}
+					else {
+						// THIS IS SPOT NUMBER 2
+						// You have to include CSS options in another place as well
+						// see spot number 1
+						if (!useInlineStyles) {
+							styles += "\n" + cssOutput;
+						}
+						
+						if (css) {
+							styles += "\n" + css;
+						}
+						
+						if (useSVGButtonClass) {
+							styles += "\n" + buttonCSS2;
+						}
+						
+						if (showBorders) {
+							styles += "\n" + showBordersCSS;
+						}
+						
+						
+						if (addZoom) {
+							//zoomOutput = zoomCSS.replace(/IFRAME_ID/g, "#" + application.name);
+							zoomOutput = zoomCSS.replace(/IFRAME_ID/g, "#" + zoomInID);
+							zoomOutput = zoomOutput.replace(/ZOOM_VALUE/g, iDocument.scale);
+							styles += "\n" + zoomOutput;
+						}
+						
+						
+						
+						
+						// add styles in style tags and add to output
+						if (styles!="") {
+							output += "\n" + wrapInStyleTags(styles);
+						}
+						
+						
+						
+						if (showFullHTMLPageSource) {
+							output = template.replace(contentToken, output);
+						}
+					}
+					
+							
+					isValid = XMLUtils.isValidXML(output);
+					
+					if (!isValid) {
+						error = XMLUtils.validationError;
+						errorMessage = XMLUtils.validationErrorMessage;
+					}
+					else {
+						error = null;
+						errorMessage = null;
+					}
+			
+					var checkValidXML:Boolean = false;
+					if (checkValidXML) {
+						try {
+							// don't use XML for HTML output because it converts this:
+							// <div ></div>
+							// to this:
+							// <div />
+							// and that breaks the html page
+							
+							// we can still try it to make sure it's valid
+							// we could be saving CPU cycles here?
+							var time:int = getTimer();
+							
+							// check if valid XML
+							// we could also use XMLUtils.isValid but this is also for formatting
+							xml = new XML(output);
+							time = getTimer() -time;
+							//trace("xml validation parsing time=" + time);
+							sourceCode = output;
+						}
+						catch (error:Error) {
+							// Error #1083: The prefix "s" for element "Group" is not bound.
+							// <s:Group x="93" y="128">
+							//	<s:Button x="66" y="17"/>
+							//</s:Group>
+							time = getTimer() -time;
+							//trace("xml validation parsing time with error=" + time);
+							sourceCode = output;
+						}
+					}
+					else {
+						sourceCode = output;
+					}
+				}
+				else {// this should not be here - it should be in DocumentData
+					XML1 = <document />;
+					XML1.@host = iDocument.host;
+					XML1.@id = iDocument.id;
+					XML1.@name = iDocument.name;
+					XML1.@uid = iDocument.uid;
+					XML1.@uri = iDocument.uri;
+					output = XML1.toXMLString();
+				}
+			}
+			
+			return output;
+		}
+		
+	
+		
+		/**
+		 * Gets the formatted output from a component.
+		 * Yes, this is a mess. It needs refactoring.  
+		 * I wanted to see if I could quickly generate valid HTML 
+		 * from the component tree. 
+		 * 
+		 * There is partial work with CSS properties objects but those are not implemented yet. 
+		 * */
+		public function getHTMLOutputString(iDocument:IDocument, component:ComponentDescription, addLineBreak:Boolean = false, tabs:String = "", includePreview:Boolean = false):String {
+			var property:Object = component.properties;
+			var componentName:String = component.name ? component.name.toLowerCase() : "";
+			var htmlName:String = componentName ? componentName : "";
+			var componentChild:ComponentDescription;
+			var contentToken:String = "[child_content]";
+			var styleValue:String = "position:absolute;";
+			var styles:Styles = new Styles();
+			var wrapperStyles:Styles = new Styles();
+			var isHorizontalLayout:Boolean;
+			var isVerticalLayout:Boolean;
+			var isBasicLayout:Boolean;
+			var isTileLayout:Boolean;
+			var childContent:String = "";
+			var wrapperTag:String = "";
+			var centeredHorizontally:Boolean;
+			var wrapperTagStyles:String = "";
+			var properties:String = "";
+			var outlineStyle:String;
+			var output:String = "";
+			var type:String = "";
+			var instance:Object;
+			var numElements:int;
+			var index:int;
+			var value:*;
+			var gap:int;
+			
+			
+			// we are setting the styles in a string now
+			// the next refactor should use the object so we can output to CSS
+			styles.position = Styles.ABSOLUTE;
+			outlineStyle = "outline:1px solid red;"; // we should enable or disable outlines via code not markup on in the export
+			
+			// get layout positioning
+			if (component.parent && component.parent.instance is IVisualElementContainer) {
+				
+				if (component.parent.instance.layout is HorizontalLayout) {
+					isHorizontalLayout = true;
+					styleValue = styleValue.replace("absolute", "relative");
+					//styleValue += "vertical-align:middle;";
+					styles.position = Styles.RELATIVE;
+					index = GroupBase(component.parent.instance).getElementIndex(component.instance as IVisualElement);
+					numElements = GroupBase(component.parent.instance).numElements;
+					wrapperTagStyles += hasExplicitSizeSet(component.instance as IVisualElement) ? "display:inline-block;" : "display:inline;";
+					wrapperStyles.display = hasExplicitSizeSet(component.instance as IVisualElement) ? Styles.INLINE_BLOCK : Styles.INLINE;
+					gap = HorizontalLayout(component.parent.instance.layout).gap - 4;
+					
+					
+					if (index<numElements-1 && numElements>1) {
+						//wrapperTagStyles += "padding-right:" + gap + "px;";
+						wrapperTagStyles += Styles.MARGIN_RIGHT+":" + gap + "px;";
+						wrapperStyles.marginRight =  gap + "px";
+						
+					}
+					
+					wrapperTag = "div";
+				}
+				else if (component.parent.instance.layout is TileLayout) {
+					//isHorizontalLayout = true;
+					isTileLayout = true;
+					styleValue = styleValue.replace("absolute", "relative");
+					styles.position = Styles.RELATIVE;
+					index = GroupBase(component.parent.instance).getElementIndex(component.instance as IVisualElement);
+					numElements = GroupBase(component.parent.instance).numElements;
+					wrapperTagStyles += hasExplicitSizeSet(component.instance as IVisualElement) ? "display:inline-block;" : "display:inline;";
+					wrapperStyles.display = hasExplicitSizeSet(component.instance as IVisualElement) ? Styles.INLINE_BLOCK : Styles.INLINE;
+					gap = TileLayout(component.parent.instance.layout).horizontalGap - 4;
+					
+					if (index<numElements-1 && numElements>1) {
+						//wrapperTagStyles += "padding-right:" + gap + "px;";
+						// using "margin-right" because if you set a fixed width padding was not doing anything
+						wrapperTagStyles += Styles.MARGIN_RIGHT+":" + gap + "px;";
+						//wrapperStyles.paddingRight =  gap + "px";
+						wrapperStyles.marginRight =  gap + "px";
+					}
+					
+					wrapperTag = "div";
+				}
+				
+				else if (component.parent.instance.layout is VerticalLayout) {
+					isVerticalLayout = true;
+					styleValue = styleValue.replace("absolute", "relative");
+					styles.position = Styles.RELATIVE;
+					index = GroupBase(component.parent.instance).getElementIndex(component.instance as IVisualElement);
+					numElements = GroupBase(component.parent.instance).numElements;
+					gap = VerticalLayout(component.parent.instance.layout).gap;
+					
+					
+					if (index<numElements-1 && numElements>1) {
+						//wrapperTagStyles += "padding-bottom:" + gap + "px;";
+						wrapperTagStyles += Styles.MARGIN_BOTTOM+":" + gap + "px;";
+						//wrapperStyles.paddingBottom =  gap + "px";
+						wrapperStyles.marginBottom =  gap + "px";
+					}
+					
+					wrapperTag = "div";
+				}
+				
+				else if (component.parent.instance.layout is BasicLayout) {
+					isBasicLayout = true;
+					
+					
+					
+					//styleValue = styleValue.replace("absolute", "relative");
+					//styles.position = Styles.RELATIVE;
+					/*index = GroupBase(component.parent.instance).getElementIndex(component.instance as IVisualElement);
+					numElements = GroupBase(component.parent.instance).numElements;
+					gap = BasicLayout(component.parent.instance.layout).gap;*/
+					
+					/*if (index<numElements-1 && numElements>1) {
+						wrapperTagStyles += "padding-bottom:" + gap + "px";
+					}
+					
+					wrapperTag = "div";*/
+				}
+			}
+			
+			// constraints take higher authority
+			var isHorizontalSet:Boolean;
+			var isVerticalSet:Boolean;
+			
+			// loop through assigned properties
+			for (var propertyName:String in property) {
+				value = property[propertyName];
+				
+				if (value===undefined || value==null) {
+					continue;
+				}
+				
+				
+				if (verticalPositions.indexOf(propertyName)!=-1 && !isVerticalSet) {
+					styleValue = getVerticalPositionHTML(component.instance as IVisualElement, styles, styleValue, isBasicLayout);
+					isVerticalSet = true;
+				}
+				else if (horizontalPositions.indexOf(propertyName)!=-1 && !isHorizontalSet) {
+					styleValue = getHorizontalPositionHTML(component.instance as IVisualElement, styles, styleValue, isBasicLayout);
+					isHorizontalSet = true;
+				}
+				
+			}
+			
+			
+			if (htmlName) {
+				
+				// create code for element type
+				if (htmlName=="application") {
+					htmlName = "div";
+					
+					// container div
+					if (includePreview) {
+						/*output = "<div style=\"position:absolute;";
+						//output += "width:" + (component.instance.width + 40) + "px;";
+						output += "width:100%;";
+						output += "height:" + (component.instance.height + 40) + "px;";
+						output += "background-color:#666666;\">";*/
+						output += "<div";
+						//output = getNameString(component.instance, output);
+						output += properties ? " " + properties : " ";
+						output = getIdentifierAttribute(component.instance, output);
+						styleValue = styleValue.replace("absolute", "relative");
+						styles.position = Styles.ABSOLUTE;
+						styleValue += "width:" + component.instance.width+ "px;";
+						styleValue += "height:" + component.instance.height+ "px;";
+						styleValue += "font-family:" + component.instance.getStyle("fontFamily") + ";";
+						styleValue += "font-size:" + component.instance.getStyle("fontSize") + "px;";
+						styleValue += "margin:0 auto;";
+						styleValue += "left:8px;top:14px;";
+						styleValue += "overflow:auto;";
+						styleValue += "background-color:" + DisplayObjectUtils.getColorInHex(component.instance.getStyle("backgroundColor"), true) + ";";
+						//output += properties ? " " : "";
+						output += setStyles(component.instance, styleValue);
+
+						
+						if (showScreenshotBackground) {
+							var backgroundImageID:String = "backgroundComparisonImage";
+							var imageDataFormat:String = "png";//"jpeg";
+							var imageData:String = getDataURI(component.instance, imageDataFormat);
+							var backgroundSnapshot:String = "\n" + tabs + "\t" + "<img ";
+							backgroundSnapshot += "id=\"" + backgroundImageID +"\""; 
+							backgroundSnapshot += " src=\"" + imageData + "\" ";
+							
+							output += backgroundSnapshot;
+							output += setStyles("#"+backgroundImageID, "position:absolute;opacity:"+backgroundImageAlpha+";top:0px;left:0px;", true);
+							/* background-image didn't work in FF on mac. didn't test on other browsers
+							//trace(imageData);
+							var imageDataStyle:String = "#" + getIdentifierOrName(target) + "  {\n";
+							//imageDataStyle = "\tbackground-image: url(data:image/jpeg;base64,"+imageData+");";
+							imageDataStyle += "\tbackground-repeat: no-repeat;\n";
+							imageDataStyle += "\tbackground-image: url(data:image/"+imageDataFormat+";base64,"+imageData+");\n}";
+							styles += "\n" + imageDataStyle;*/
+						}
+						
+						output += contentToken;
+						//output += "\n </div>\n</div>";
+						output += "\n</div>";
+						
+					}
+					else {
+						//output = "<div style=\"position: absolute;width:100%;height:100%;background-color:#666666;\">";
+						output = "<div";
+						output += properties ? " " + properties : " ";
+						output = getIdentifierAttribute(component.instance, output);
+						//output = getNameString(component.instance, output);
+						output += properties ? " " + properties : "";
+						styleValue += "width:" + component.instance.width+ "px;";
+						styleValue += "height:" + component.instance.height+ "px;";
+						styleValue += "border:1px solid black";
+						styleValue += "background-color:" + DisplayObjectUtils.getColorInHex(component.instance.getStyle("backgroundColor"), true) + ";";
+						//output += properties ? " " : "";
+						output += setStyles(component.instance, styleValue);
+						output += contentToken;
+						output += "\n</div>";
+					}
+				}
+				
+				else if (htmlName=="group" || htmlName=="vgroup") {
+					htmlName = "div";
+					output = tabs + getWrapperTag(wrapperTag, false, wrapperTagStyles);
+					output += "<div " + properties;
+					output = getIdentifierAttribute(component.instance, output);
+					output += properties ? " " : "";
+					styleValue = getSizeString(component.instance as IVisualElement, styleValue, isHorizontalSet);
+					
+					//styleValue += "width:" + component.instance.width+ "px;";
+					//styleValue += "height:" + component.instance.height+ "px;";
+					output += setStyles(component.instance, styleValue);
+					output += contentToken;
+					output += "\n" + tabs + "</div>";
+					output += getWrapperTag(wrapperTag, true);
+				}
+				
+				else if (htmlName=="bordercontainer") {
+					htmlName = "div";
+					output = tabs + getWrapperTag(wrapperTag, false, wrapperTagStyles);
+					output += "<div " + properties;
+					output = getIdentifierAttribute(component.instance, output);
+					output += properties ? " " : "";
+					styleValue = getSizeString(component.instance as IVisualElement, styleValue, isHorizontalSet);
+					styleValue += getBorderString(component.instance as BorderContainer);
+					//styleValue += getColorString(component.instance as BorderContainer);
+					//styles += component.instance as BorderContainer);
+					
+					output += setStyles(component.instance, styleValue);
+					output += contentToken;
+					output += "\n" + tabs + "</div>";
+					output += getWrapperTag(wrapperTag, true);
+					
+				}
+				
+				else if (htmlName=="hgroup" || htmlName=="tilegroup") {
+					htmlName = "div";
+					output = tabs + getWrapperTag(wrapperTag, false, wrapperTagStyles);
+					output += "<div " + properties;
+					output = getIdentifierAttribute(component.instance, output);
+					
+					//styleValue = getSizeString(component.instance as IVisualElement, styleValue);
+					if (component.name=="HGroup") {
+						styleValue += "width:" + Math.max(HGroup(component.instance).contentWidth, component.instance.width)+ "px;";
+					}
+					else {
+						styleValue += "width:" + component.instance.width+ "px;";
+					}
+					
+					styleValue += "height:" + component.instance.height+ "px;";
+					//var verical:String = component.instance.getStyle("verticalAlign");
+					var vericalAlign:String = component.instance.verticalAlign;
+					if (componentName.toLowerCase()=="hgroup" && vericalAlign=="middle") {
+						styleValue += "line-height:" + component.instance.height + "px;";
+					}
+					
+					output += properties ? " " : "";
+					output += setStyles(component.instance, styleValue);
+					output += contentToken;
+					output += "\n" + tabs + "</div>";
+					output += getWrapperTag(wrapperTag, true);
+				}
+				else if (htmlName=="button" || htmlName=="togglebutton") {
+					htmlName = "button";
+					output = tabs + getWrapperTag(wrapperTag, false, wrapperTagStyles);
+					output += "<input " + properties;
+					output = getIdentifierAttribute(component.instance, output);
+					output += " type=\"" + htmlName.toLowerCase() + "\"" ;
+					output += properties ? " " + properties : "";
+					styleValue = getSizeString(component.instance as IVisualElement, styleValue, isHorizontalSet);
+					styleValue += "font-family:" + component.instance.getStyle("fontFamily") + ";";
+					styleValue += "font-size:" + component.instance.getStyle("fontSize") + "px;";
+					output += " value=\"" + component.instance.label + "\"";
+					output += " class=\"buttonSkin\"";
+					output += setStyles(component.instance, styleValue);
+					
+					output += getWrapperTag(wrapperTag, true);
+				}
+				else if (htmlName=="checkbox") {
+					if (component.instance.label!="") {
+						output = tabs + getWrapperTag(wrapperTag, false, wrapperTagStyles);
+						output += "<label ";
+						output = getIdentifierAttribute(component.instance, output, "_Label");
+						styleValue = getSizeString(component.instance as IVisualElement, styleValue, isHorizontalSet);
+						//styleValue += "width:" + (component.instance.width + 6)+ "px;";
+						//styleValue += "height:" + component.instance.height+ "px;";
+						styleValue += "font-family:" + component.instance.getStyle("fontFamily") + ";";
+						styleValue += "font-size:" + component.instance.getStyle("fontSize") + "px;";
+						output += setStyles("#"+getIdentifierOrName(component.instance, true, "_Label"), styleValue);
+						output += "<input ";
+						output = getIdentifierAttribute(component.instance, output);
+						output += " type=\"" + htmlName.toLowerCase() + "\" ";
+						output += "/>" ;
+					}
+					else {
+						output = tabs + getWrapperTag(wrapperTag, false, wrapperTagStyles);
+						output += "<input " + properties;
+						output = getIdentifierAttribute(component.instance, output);
+						output += " type=\"" + htmlName.toLowerCase() + "\" " + properties;
+						//styleValue = getSizeString(component.instance as IVisualElement, styleValue);
+						output += setStyles(component.instance, styleValue);
+					}
+					
+					if (component.instance.label!="") {
+						output += " " + component.instance.label + "</label>";
+					}
+					
+					output += getWrapperTag(wrapperTag, true);
+				}
+				else if (htmlName=="radiobutton") {
+					htmlName = "radio";
+					if (component.instance.label!="") {
+						output = tabs + getWrapperTag(wrapperTag, false, wrapperTagStyles);
+						output += "<label ";
+						output = getIdentifierAttribute(component.instance, output, "_Label");
+						//styleValue += "width:" + (component.instance.width + 8)+ "px;";
+						//styleValue += "height:" + component.instance.height+ "px;";
+						styleValue = getSizeString(component.instance as IVisualElement, styleValue, isHorizontalSet);
+						styleValue += "font-family:" + component.instance.getStyle("fontFamily") + ";";
+						styleValue += "font-size:" + component.instance.getStyle("fontSize") + "px;";
+						output += setStyles("#"+getIdentifierOrName(component.instance, true, "_Label"), styleValue);
+						output += "<input type=\"radio\" " ;
+						output = getIdentifierAttribute(component.instance, output);
+						//styleValue = getSizeString(component.instance as IVisualElement, styleValue);
+						output += "/>" ;
+					}
+					else {
+						output = tabs + getWrapperTag(wrapperTag, false, wrapperTagStyles);
+						output += "<input type=\"" + htmlName.toLowerCase() + "\" " + properties;
+						output = getIdentifierAttribute(component.instance, output);
+						styleValue = getSizeString(component.instance as IVisualElement, styleValue, isHorizontalSet);
+						//styleValue = getSizeString(component.instance as IVisualElement, styleValue);
+						output += setStyles(component.instance, styleValue);
+					}
+					
+					if (component.instance.label!="") {
+						output += " " + component.instance.label + "</label>";
+					}
+					
+					output += getWrapperTag(wrapperTag, true);
+				}
+				else if (htmlName=="textinput" || htmlName=="combobox") {
+					htmlName = "input";
+					output = tabs + getWrapperTag(wrapperTag, false, wrapperTagStyles);
+					output += "<input ";
+					output = getIdentifierAttribute(component.instance, output);
+					output += " type=\"input\" "  + properties;
+					//styleValue += "width:" + component.instance.width+ "px;";
+					//styleValue += "height:" + component.instance.height+ "px;";
+					styleValue = getSizeString(component.instance as IVisualElement, styleValue, isHorizontalSet);
+					styleValue += "font-family:" + component.instance.getStyle("fontFamily") + ";";
+					styleValue += "font-size:" + component.instance.getStyle("fontSize") + "px;";
+					styleValue += "padding:0;border:1px solid " + DisplayObjectUtils.getColorInHex(component.instance.getStyle("borderColor"), true) + ";";
+					
+					if (htmlName=="combobox") {
+						output += " list=\"listdata\"";
+						//<datalist id="listData">
+							  //<option value="value 1">
+							  //<option value="value 2">
+							  //<option value="value 3">
+							//</datalist> 
+					}
+					output += setStyles(component.instance, styleValue);
+					output += getWrapperTag(wrapperTag, true);
+				}
+				else if (htmlName=="dropdownlist") {
+					htmlName = "select";
+					output = tabs + getWrapperTag(wrapperTag, false, wrapperTagStyles);
+					output += "<select ";
+					output = getIdentifierAttribute(component.instance, output);
+					output += " type=\"input\" "  + properties;
+					//styleValue += "width:" + component.instance.width+ "px;";
+					//styleValue += "height:" + component.instance.height+ "px;";
+					styleValue = getSizeString(component.instance as IVisualElement, styleValue, isHorizontalSet);
+					styleValue += "font-family:" + component.instance.getStyle("fontFamily") + ";";
+					styleValue += "font-size:" + component.instance.getStyle("fontSize") + "px;";
+					styleValue += "padding:0;border:1px solid " + DisplayObjectUtils.getColorInHex(component.instance.getStyle("borderColor"), true) + ";";
+					
+					output += setStyles(component.instance, styleValue);
+					output += "</select>";
+					output += getWrapperTag(wrapperTag, true);
+				}
+				else if (htmlName=="linkbutton") {
+					htmlName = "a";
+					output = tabs + getWrapperTag(wrapperTag, false, wrapperTagStyles);
+					output += "<a "  + properties;
+					output = getIdentifierAttribute(component.instance, output);
+					//styleValue += "width:" + component.instance.width+ "px;";
+					//styleValue += "height:" + component.instance.height+ "px;";
+					styleValue = getSizeString(component.instance as IVisualElement, styleValue, isHorizontalSet);
+					styleValue += "font-family:" + component.instance.getStyle("fontFamily") + ";";
+					styleValue += "font-size:" + component.instance.getStyle("fontSize") + "px;";
+					//styles += getBorderString(component.instance as IStyleClient);
+					
+					output += properties ? " " : "";
+					output += setStyles(component.instance, styleValue);
+					output += component.instance.label;
+					output += "</a>";
+					output += getWrapperTag(wrapperTag, true);
+				}
+				else if (htmlName=="label") {
+					htmlName = "label";
+					if (useWrapperDivs) {
+						output = tabs + getWrapperTag(wrapperTag, false, wrapperTagStyles);
+					}
+					else {
+						output = tabs;
+					}
+					output += "<label "  + properties;
+					output = getIdentifierAttribute(component.instance, output);
+					//styleValue += "width:" + component.instance.width+ "px;";
+					//styleValue += "height:" + component.instance.height+ "px;";
+					styleValue = getSizeString(component.instance as IVisualElement, styleValue, isHorizontalSet, isVerticalSet);
+					//styleValue += wrapperTagStyles;
+					styleValue += "color:" + DisplayObjectUtils.getColorInHex(component.instance.getStyle("color"), true) + ";";
+					styleValue += "font-weight:" + component.instance.getStyle("fontWeight") + ";";
+					styleValue += "font-family:" + component.instance.getStyle("fontFamily") + ";";
+					styleValue += "font-size:" + component.instance.getStyle("fontSize") + "px;";
+					styleValue += "line-height:" + "1;";
+					//styles += getBorderString(component.instance as IStyleClient);
+					
+					output += properties ? " " : "";
+					// remove wrapperTagStyles since we are trying to not use wrapper tags
+					//output += setStyles(component.instance, styleValue+wrapperTagStyles);
+					output += setStyles(component.instance, wrapperTagStyles+styleValue);
+					output += component.instance.text;
+					output += "</label>";
+					if (useWrapperDivs) {
+						output += getWrapperTag(wrapperTag, true);
+					}
+				}
+				else if (htmlName=="image") {
+					htmlName = "img";
+					output = tabs + getWrapperTag(wrapperTag, false, wrapperTagStyles);
+					output += "<img " + properties;
+					output = getIdentifierAttribute(component.instance, output);
+					//styleValue += "width:" + component.instance.width+ "px;";
+					//styleValue += "height:" + component.instance.height+ "px;";
+					styleValue = getSizeString(component.instance as IVisualElement, styleValue, isHorizontalSet);
+					output += properties ? " " : "";
+					
+					if (component.instance.source is BitmapData) {
+						output += " src=\"" + getDataURI(component.instance.source, "jpeg") + "\"";
+					}
+					else if (component.instance.source is String) {
+						output += " src=\"" + component.instance.source + "\"";
+					}
+					output += setStyles(component.instance, styleValue);
+					output += getWrapperTag(wrapperTag, true);
+				}
+				
+				else {
+					// show placeholder NOT actual component
+					htmlName = "label";
+					if (useWrapperDivs) {
+						output = tabs + getWrapperTag(wrapperTag, false, wrapperTagStyles);
+					}
+					else {
+						output = tabs;
+					}
+					output += "<label "  + properties;
+					output = getIdentifierAttribute(component.instance, output);
+					//styleValue += "width:" + component.instance.width+ "px;";
+					//styleValue += "height:" + component.instance.height+ "px;";
+					styleValue = getSizeString(component.instance as IVisualElement, styleValue, isHorizontalSet, isVerticalSet);
+					//styleValue += wrapperTagStyles;
+					styleValue += "color:" + DisplayObjectUtils.getColorInHex(component.instance.getStyle("color"), true) + ";";
+					styleValue += "font-weight:" + component.instance.getStyle("fontWeight") + ";";
+					styleValue += "font-family:" + component.instance.getStyle("fontFamily") + ";";
+					styleValue += "font-size:" + component.instance.getStyle("fontSize") + "px;";
+					styleValue += "line-height:" + "1;";
+					//styles += getBorderString(component.instance as IStyleClient);
+					
+					output += properties ? " " : "";
+					// remove wrapperTagStyles since we are trying to not use wrapper tags
+					//output += setStyles(component.instance, styleValue+wrapperTagStyles);
+					output += setStyles(component.instance, wrapperTagStyles+styleValue);
+					output += getIdentifierOrName(component.instance);
+					output += "</label>";
+					if (useWrapperDivs) {
+						output += getWrapperTag(wrapperTag, true);
+					}
+					/*
+					output = tabs + getWrapperTag(wrapperTag, false, wrapperTagStyles);
+					output += "<" + htmlName.toLowerCase()  + " " + properties;
+					output = getIdentifierAttribute(component.instance, output);
+					styleValue = getSizeString(component.instance as IVisualElement, styleValue, isHorizontalSet);
+					output += properties ? " " : "";
+					output += setStyles(component.instance, styleValue);
+					output += getWrapperTag(wrapperTag, true);*/
+				}
+				
+				
+				// add children
+				if (component.children && component.children.length>0) {
+					//output += ">\n";
+					
+					for (var i:int;i<component.children.length;i++) {
+						componentChild = component.children[i];
+						getAppliedPropertiesFromHistory(iDocument, componentChild);
+						if (i>0) {
+							childContent += "\n";
+						}
+						childContent += getHTMLOutputString(iDocument, componentChild, false, tabs + "\t");
+					}
+					
+					output = output.replace(contentToken, "\n" + childContent);
+
+				}
+				else {
+					output = output.replace(contentToken, "\n");
+				}
+			}
+			else {
+				output = "";
+			}
+			
+			return output;
+		}
+		
+		/**
+		 * Get a tag with less than or greater than wrapped around it. 
+		 * */
+		private function getWrapperTag(wrapperTag:String = "", end:Boolean = false, styles:String = ""):String {
+			var output:String = "";
+			
+			if (wrapperTag=="") return "";
+			
+			if (end) {
+				output = "</" + wrapperTag + ">";
+				return output;
+			}
+			
+			output += "<" + wrapperTag;
+			
+			if (styles) {
+				output += " style=\"" + styles + "\"" ;
+			}
+			
+			output += ">";
+			
+			return output;
+		}
+		
+		/**
+		 * Get width and height styles
+		 * If explicit width is set then we should use inline-block 
+		 * because inline does not respect width and height
+		 * */
+		public function getSizeString(instance:IVisualElement, styleValue:String = "", isHorizontalAlignSet:Boolean = false, isVerticalSet:Boolean = false):String {
+			var hasExplicitSize:Boolean;
+			var hasBorder:Boolean;
+			var border:int;
+			
+			if (instance is IStyleClient && IStyleClient(instance).getStyle("borderWeight")) {
+				
+			}
+			
+			if (!isNaN(instance.percentWidth)) {
+				styleValue += "width:" + instance.percentWidth + "%;";
+			}
+			else if ("explicitWidth" in instance) {
+				if (Object(instance).explicitWidth!=null && !isNaN(Object(instance).explicitWidth)
+					|| setExplicitSize) {
+					styleValue += "width:" + instance.width + "px;";
+					hasExplicitSize = true;
+				}
+			}
+			else {
+				//styleValue += "width:" + instance.width + "px;";
+			}
+			
+			if (!isNaN(instance.percentHeight)) {
+				styleValue += "height:" + instance.percentHeight + "%;";
+			}
+			else if ("explicitHeight" in instance) {
+				if (Object(instance).explicitHeight!=null && !isNaN(Object(instance).explicitHeight)
+					|| setExplicitSize) {
+					styleValue += "height:" + instance.height + "px;";
+					hasExplicitSize = true;
+				}
+			}
+			else {
+				//styleValue += "height:" + instance.height + "px;";
+			}
+			
+			
+			// If explicit width is set then we should use inline-block 
+			// because inline does not respect width and height
+			if (!isHorizontalAlignSet && hasExplicitSize) {
+				styleValue += "display:" + Styles.INLINE_BLOCK + ";";
+			}
+			
+			return styleValue;
+			
+		}
+		
+		/**
+		 * Checks if size is explicitly set
+		 * If explicit width is set then we should use inline-block 
+		 * because inline does not respect width and height
+		 * */
+		public function hasExplicitSizeSet(instance:IVisualElement):Boolean {
+			
+			if ("explicitWidth" in instance && Object(instance).explicitWidth!=null) {
+				return true;
+			}
+			else if ("explicitHeight" in instance && Object(instance).explicitHeight!=null) {
+				return true;
+			}
+			
+			return false;
+		}
+			
+		/**
+		 * Get the horizontal position string for HTML
+		 * */
+		public function getHorizontalPositionHTML(instance:IVisualElement, propertyModel:Styles, stylesValue:String = "", isBasicLayout:Boolean = true):String {
+			
+			if (!isBasicLayout) return stylesValue;
+			// horizontal center trumps left and x properties
+			if (instance.horizontalCenter!=null) {
+				stylesValue += "display:block;margin:" + instance.horizontalCenter + " auto;left:0;right:0;";
+				//stylesValue = stylesValue.replace("absolute", "relative");
+				
+				propertyModel.display = Styles.BLOCK;
+				//propertyModel.position = Styles.RELATIVE;
+				propertyModel.position = Styles.ABSOLUTE;
+				propertyModel.margin = instance.horizontalCenter + " auto;left:0;right:0;";
+				
+				return stylesValue;
+			}
+			else if (instance.left!=null || instance.right!=null) {
+				stylesValue += instance.left!=null ? "left:" + instance.left + "px;" : "";
+				stylesValue += instance.right!=null ? "right:" + instance.right + "px;" : "";
+				if (instance.left!=null) propertyModel.left = instance.left + "px";
+				if (instance.right!=null) propertyModel.right = instance.right + "px";
+				return stylesValue;
+			}
+			else {
+				stylesValue += "left:" + instance.x + "px;";
+				propertyModel.left = instance.x + "px;";
+			}
+			
+			return stylesValue;
+		}
+		
+			
+		/**
+		 * Get the vertical position string for HTML
+		 * */
+		public function getVerticalPositionHTML(instance:IVisualElement, propertyModel:Styles, stylesValue:String = "", isBasicLayout:Boolean = true):String {
+			
+			if (!isBasicLayout) return stylesValue;
+			
+			if (instance.verticalCenter!=null) {
+				stylesValue += "display:block;margin:" + instance.verticalCenter + " auto;";
+				stylesValue = stylesValue.replace("absolute", "relative");
+				
+				propertyModel.display = Styles.BLOCK;
+				propertyModel.position = Styles.RELATIVE;
+				propertyModel.margin = instance.verticalCenter + " auto;";
+				
+				return stylesValue;
+			}
+			else if (instance.top!=null || instance.bottom!=null) {
+				stylesValue += instance.top!=null ? "top:" + instance.top + "px;" : "";
+				stylesValue += instance.bottom!=null ? "bottom:" + instance.bottom + "px;" : "";
+				if (instance.top!=null) propertyModel.top = instance.top + "px";
+				if (instance.bottom!=null) propertyModel.bottom = instance.bottom + "px";
+				return stylesValue;
+			}
+			else {
+				stylesValue += "top:" + instance.y + "px;";
+				propertyModel.top = instance.y + "px;";
+			}
+			
+			return stylesValue;
+		}
+		
+		/**
+		 * Get border and background styles of a border container
+		 * */
+		public function getBorderString(element:IStyleClient):String {
+			var value:String = "";
+			
+			if (element.getStyle("backgroundAlpha")!=0) {
+				value += "background-color:" + DisplayObjectUtils.getColorInHex(element.getStyle("backgroundColor"), true) + ";";
+				value += "background-alpha:" + element.getStyle("backgroundAlpha") + ";";
+			}
+			
+			if (element.getStyle("borderVisible")) {
+				value += "border-width:" + element.getStyle("borderWeight") + "px;";
+				value += "border-style:solid;";
+				
+				if (element.getStyle("borderColor")!==undefined) {
+					value += "border-color:" + DisplayObjectUtils.getColorInHex(element.getStyle("borderColor"), true) + ";";
+				}
+			}
+			
+			if (element.getStyle("color")!==undefined) {
+				value += "color:" + DisplayObjectUtils.getColorInHex(element.getStyle("color"), true) + ";";
+			}
+			
+			return value;
+		}
+		
+		/**
+		 * Set styles
+		 * */
+		public function setStyles(component:Object, styles:String = "", singleton:Boolean = false):String {
+			var out:String = ">";
+			
+			if (useInlineStyles) {
+				return " style=\"" + styles + "\"" + (singleton?"\>":">");
+			}
+			else {
+				var formatted:String= "\t" + styles.replace(/;/g, ";\n\t");
+				
+				//styles += ";";
+				//cssOutput += "#" + getIdentifierOrName(component) + "  {\n\n";
+				//cssOutput += "" + styles.replace(/;/g, ";\n") + "\n\n}  ";
+				
+				if (component is String) {
+					out = component + " {\n";
+				}
+				else {
+					out = "#" + getIdentifierOrName(component) + "  {\n";
+				}
+				out += formatted;
+				out += "}\n\n";
+				
+				out = out.replace(/\t}/g, "}");
+				
+				cssOutput += out;
+			}
+			
+			return (singleton?"\>":">");
+		}
+		
+		
+		/**
+		 * Wrap in style tags
+		 * */
+		public function wrapInStyleTags(value:String):String {
+			var out:String = "<style>\n" + value + "\n</style>";
+			return out;
+		}
+		
+		/**
+		 * Gets the ID of the target object
+		 * 
+		 * @param name if id is not available then if the name parameter is true then use name
+		 * 
+		 * returns id or name
+		 * */
+		public function getIdentifierOrName(element:Object, name:Boolean = true, appendID:String = ""):String {
+
+			if (element && "id" in element && element.id) {
+				return element.id + appendID;
+			}
+			else if (element && name && "name" in element && element.name) {
+				return element.name + appendID;
+			}
+			
+			return "";
+		}
+		
+		/**
+		 * Get ID from ID or else name attribute
+		 * */
+		public function getIdentifierAttribute(instance:Object, value:String = "", appendID:String = ""):String {
+			
+			if (instance && "id" in instance && instance.id) {
+				value += "id=\"" + instance.id + appendID + "\"";
+			}
+			
+			else if (instance && "name" in instance && instance.name) {
+				value += "id=\"" + instance.name + appendID + "\"";
+			}
+			
+			return value;
+		}
+		
+		/**
+		 * Get name and ID attribute
+		 * */
+		public function getIdentifierOrNameAttribute(instance:Object, propertyValue:String = ""):String {
+			
+			if (instance && "id" in instance && instance.id) {
+				propertyValue += "id=\"" + instance.id + "\"";
+			}
+			
+			if (instance && "name" in instance && instance.name) {
+				propertyValue += "name=\"" + instance.name + "\"";
+			}
+			
+			return propertyValue;
+		}
+		
+		/**
+		 * @inheritDoc
+		 * */
+		public function exportXML(document:IDocument, reference:Boolean = false):XML {
+			return null;
+		}
+		
+		/**
+		 * @inheritDoc
+		 * */
+		public function exportJSON(document:IDocument, reference:Boolean = false):JSON {
+			return null;
+		}
+		
+		/**
+		 * Get data URI from object. 
+		 * 
+		 * Encoding to JPG took 2000ms in some cases where PNG took 200ms.
+		 * I have not extensively tested this but it seems to be 10x faster
+		 * than JPG. 
+		 * */
+		public function getDataURI(target:Object, type:String = "png"):String {
+			var output:String;
+			
+			if (type.toLowerCase()=="jpg") {
+				type = "jpeg";
+			}
+			
+			output = "data:image/" + type + ";base64," + getBase64ImageData(target, type);
+			
+			return output;
+		}
+		
+		/**
+		 * Returns base64 image string.
+		 * 
+		 * Encoding to JPG took 2000ms in some cases where PNG took 200ms.
+		 * I have not extensively tested this but it seems to be 10x faster
+		 * than JPG. 
+		 * 
+		 * Performance: 
+		 * get snapshot. time=14
+		 * encode to png. time=336 // encode to jpg. time=2000
+		 * encode to base 64. time=35
+		 * 
+		 * Don't trust these numbers. Test it yourself. First runs are always longer than previous. 
+		 * 
+		 * This function gets called multiple times sometimes. We may be encoding more than we have too.
+		 * But is probably a bug somewhere.  
+		 * */
+		public function getBase64ImageData(target:Object, type:String = "png", checkCache:Boolean = false):String {
+			var component:IUIComponent = target as IUIComponent;
+			var bitmapData:BitmapData;
+		    var byteArray:ByteArray;
+		    var base64Encoder:Base64Encoder;
+		    var base64Encoder2:Base64;
+			var useEncoder:Boolean;
+			var rectangle:Rectangle;
+			var jpegEncoderOptions:JPEGEncoderOptions;
+			var pngEncoderOptions:PNGEncoderOptions;
+			var quality:int = 80;
+			var fastCompression:Boolean = true;
+			var timeEvents:Boolean = false;
+			var altBase64:Boolean = true;
+			var results:String;
+			
+			
+			if (base64BitmapCache[target] && checkCache) {
+				return base64BitmapCache[target];
+			}
+			
+			if (timeEvents) {
+				var time:int = getTimer();
+			}
+			
+			if (component) {
+				bitmapData = BitmapUtil.getSnapshot(component);
+			}
+			else if (target is DisplayObject) {
+				bitmapData = DisplayObjectUtils.getBitmapDataSnapshot2(target as DisplayObject);
+			}
+			else if (target is BitmapData) {
+				bitmapData = target as BitmapData;
+			}
+			else {
+				return null;
+			}
+			
+			rectangle = new Rectangle(0, 0, bitmapData.width, bitmapData.height);
+			
+			if (timeEvents) {
+				trace ("get snapshot. time=" + (getTimer()-time));
+				time = getTimer();
+			}
+			
+			if (type=="png") {
+				
+				if (useEncoder) {
+					if (!pngEncoder) {
+						pngEncoder = new PNGEncoder();
+					}
+					
+					byteArray = pngEncoder.encode(bitmapData);
+				}
+				else {
+					if (!pngEncoderOptions) {
+						pngEncoderOptions = new PNGEncoderOptions(fastCompression);
+					}
+					
+					byteArray = bitmapData.encode(rectangle, pngEncoderOptions);
+				}
+			}
+			else if (type=="jpg" || type=="jpeg") {
+				
+				if (useEncoder) {
+					if (!jpegEncoder) {
+						jpegEncoder = new JPEGEncoder();
+					}
+					
+					byteArray = jpegEncoder.encode(bitmapData);
+				}
+				else {
+					if (!jpegEncoderOptions) {
+						jpegEncoderOptions = new JPEGEncoderOptions(quality);
+					}
+					
+					byteArray = bitmapData.encode(rectangle, jpegEncoderOptions);
+				}
+			}
+			else {
+				// raw bitmap image data
+				byteArray = bitmapData.getPixels(new Rectangle(0, 0, bitmapData.width, bitmapData.height));
+			}
+			
+			if (timeEvents) {
+				trace ("encode to " + type + ". time=" + (getTimer()-time));
+				time = getTimer();
+			}
+			
+			if (!altBase64) {
+				if (!base64Encoder) {
+					base64Encoder = new Base64Encoder();
+				}
+				
+			    base64Encoder.encodeBytes(byteArray);
+			
+				results = base64Encoder.toString();
+			}
+			else {
+				results = Base64.encode(byteArray);
+			}
+			
+		    //trace(base64.toString());
+			
+			if (timeEvents) {
+				trace ("encode to base 64. time=" + (getTimer()-time));
+			}
+			
+			base64BitmapCache[target] = results;
+			
+			return results;
+		}
+		
+		public var base64BitmapCache:Dictionary = new Dictionary(true)
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-radii8/blob/f370bfcf/Radii8Library/src/com/flexcapacitor/utils/InspectorUtils.as
----------------------------------------------------------------------
diff --git a/Radii8Library/src/com/flexcapacitor/utils/InspectorUtils.as b/Radii8Library/src/com/flexcapacitor/utils/InspectorUtils.as
new file mode 100644
index 0000000..ae388ec
--- /dev/null
+++ b/Radii8Library/src/com/flexcapacitor/utils/InspectorUtils.as
@@ -0,0 +1,500 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.utils {
+	import com.flexcapacitor.controller.Radiate;
+	import com.flexcapacitor.events.InspectorEvent;
+	import com.flexcapacitor.graphics.LayoutLines;
+	import com.flexcapacitor.model.VisualElementVO;
+	
+	import flash.desktop.Clipboard;
+	import flash.desktop.ClipboardFormats;
+	import flash.display.DisplayObject;
+	import flash.display.DisplayObjectContainer;
+	import flash.events.IEventDispatcher;
+	import flash.utils.describeType;
+	import flash.utils.getQualifiedClassName;
+	import flash.utils.getQualifiedSuperclassName;
+	
+	import mx.collections.ArrayCollection;
+	import mx.core.IVisualElement;
+	import mx.core.IVisualElementContainer;
+	import mx.core.UIComponent;
+	import mx.managers.ISystemManager;
+	import mx.utils.NameUtil;
+	import mx.utils.ObjectUtil;
+
+	public class InspectorUtils {
+
+
+		public function InspectorUtils() {
+
+
+		}
+		
+		/**
+		 * Get unqualified class name of the target object
+		 * */
+		public static function getClassName(element:Object):String {
+			var name:String = NameUtil.getUnqualifiedClassName(element);
+			return name;
+		}
+		
+		/**
+		 * Get unqualified class name of the document of the target object
+		 * returns null if element is not a UIComponent
+		 * */
+		public static function getDocumentName(element:Object):String {
+			var name:String;
+			if (element is UIComponent) {
+				name = NameUtil.getUnqualifiedClassName(UIComponent(element).document);
+			}
+			return name;
+		}
+		
+		/**
+		 * Get the type of the value passed in
+		 * */
+		public static function getValueType(value:*):String {
+			var type:String = getQualifiedClassName(value);
+			
+			if (type=="int") {
+				if (typeof value=="number") {
+					type = "Number";
+				}
+			}
+			
+			return type;
+		}
+		
+		/**
+		 * Get package of the target object
+		 * */
+		public static function getPackageName(element:Object):String {
+			var name:String = flash.utils.getQualifiedClassName(element);
+			if (name && name.indexOf("::")) {
+				name = name.split("::")[0];
+			}
+			
+			return name;
+		}
+
+		/**
+		 * Get super class name of the target object
+		 * */
+		public static function getSuperClassName(element:Object):String {
+			var name:String = flash.utils.getQualifiedSuperclassName(element);
+			if (name && name.indexOf("::")) {
+				name = name.split("::")[name.split("::").length-1]; // i'm sure theres a better way to do this
+			}
+			
+			return name;
+		}
+
+		/**
+		 * Get the package of the super class name of the target
+		 * */
+		public static function getSuperClassPackage(element:Object):String {
+			var name:String = flash.utils.getQualifiedSuperclassName(element);
+			if (name && name.indexOf("::")) {
+				name = name.split("::")[0];
+			}
+			
+			return name;
+		}
+		
+		/**
+		 * Clears outline drawn around target display object
+		 * */
+		public static function clearSelection(target:Object, systemManager:ISystemManager, remove:Boolean = false):void {
+			LayoutLines.getInstance().clear(target, systemManager, remove);
+		}
+		
+		/**
+		 * Draws outline around target display object
+		 * */
+		public static function drawSelection(target:Object, systemManager:ISystemManager):void {
+			throw new Error("CANNOT USE DRAW SELECTION");
+			//Radiate.drawSelection(target);
+			/*if (target is DisplayObject) {
+				LayoutLines.getInstance().drawLines(target, systemManager);
+			}
+			else if (target!=null) {
+				trace("Is not displayObject", NameUtil.getUnqualifiedClassName(target));
+			}*/
+		}
+
+		/**
+		 * Copy text to clipboard
+		 * */
+		public static function copyToClipboard(text:String, format:String=ClipboardFormats.TEXT_FORMAT):void {
+			Clipboard.generalClipboard.setData(ClipboardFormats.TEXT_FORMAT, text);
+		}
+
+		/**
+		 * Returns an array of display objects of type VisualElementVO
+		 * Optionally returns elements
+		 * */
+		public static function getElementChildrenArray(displayObject:DisplayObject, getElements:Boolean = false, getSkins:Boolean = true):ArrayCollection {
+			var displayObject:DisplayObject = DisplayObject(displayObject);
+			var displayObjectContainer:DisplayObjectContainer;
+
+			var visualElementContainer:IVisualElementContainer;
+			var visualElement:IVisualElement;
+
+			var visualElementVO:VisualElementVO = new VisualElementVO();
+
+			var children:ArrayCollection = new ArrayCollection();
+
+
+			// attempt to cast to a specific type and assign in the process
+			displayObjectContainer = displayObject as DisplayObjectContainer;
+			visualElementContainer = displayObject as IVisualElementContainer;
+			visualElement = displayObject as IVisualElement;
+
+
+			// gather all the display objects on the current display object
+			if (displayObjectContainer) {
+
+				for (var bb:int = 0; bb < displayObjectContainer.numChildren; bb++) {
+					
+						// visualElementVO = createDisplayObjectVO(displayObjectContainer.getChildAt(bb));
+					visualElementVO = VisualElementVO.unmarshall(displayObjectContainer.getChildAt(bb));
+					children.addItem(visualElementVO);
+				}
+			}
+
+			if (visualElementContainer && getElements) {
+
+				for (var cc:int = 0; cc < visualElementContainer.numElements; cc++) {
+						//visualElementVO = createDisplayObjectVO(displayObjectContainer.getChildAt(cc));
+					visualElementVO = VisualElementVO.unmarshall(DisplayObject(visualElementContainer.getElementAt(cc)));
+					children.addItem(visualElementVO);
+				}
+			}
+
+			return children;
+		}
+
+
+		/**
+		 * Gets the ID of the target object
+		 * returns null if no ID is specified or target is not a UIComponent
+		 * */
+		public static function getIdentifier(element:Object):String {
+			var id:String;
+
+			if (element is UIComponent && UIComponent(element).id) {
+				id = UIComponent(element).id;
+			}
+			return id;
+		}
+
+		/**
+		 * Get name of target object or null if not available
+		 * */
+		public static function getName(element:Object):String {
+			var name:String;
+
+			if (element.hasOwnProperty("name") && element.name) {
+				name = element.name;
+			}
+
+			return name;
+		}
+
+		/**
+		 * Get qualified class name of the target object
+		 * */
+		public static function getQualifiedClassName(element:Object):String {
+			var name:String = flash.utils.getQualifiedClassName(element);
+			return name;
+		}
+
+		/**
+		 * With the given target it returns a regexp pattern to find the exact instance in MXML
+		 * If isScript is true it attempts to returns a pattern to find the exact instance in AS3
+		 * The MXML pattern will find the instance with that ID. If the instance doesn't have an ID it no worky.
+		 * NOTE: Press CMD+SHIFT+F to and check regular expression in the Find in Files dialog
+		 * */
+		public static function getRegExpSearchPattern(target:DisplayObject, isScript:Boolean = false):String {
+			var id:String = getIdentifier(target);
+			var className:String = NameUtil.getUnqualifiedClassName(target);
+			var pattern:String;
+			var scriptPattern:String;
+
+			if (id == null) {
+				pattern = className + "(.*)";
+			}
+			else {
+				pattern = className + "(.*)id\\s?=\\s?[\"|']" + id + "[\"|']";
+				scriptPattern = id + ".addEventListener";
+			}
+
+
+			if (isScript) {
+				return scriptPattern;
+			}
+
+			return pattern;
+		}
+
+
+		/**
+		 * Get ancestors of element 
+		 * 
+		 * @param target
+		 * @param collection
+		 * @param ancestors
+		 * @return
+		 */
+		public static function getVisualElementsArray(element:*, items:Array, ancestors:int = 0, topMostDisplayObject:Object = null):Array {
+			var vo:VisualElementVO;
+
+			// do the worm up the display list
+			while (element!= null && ancestors>-1)
+			{
+				// store display element information
+				vo = VisualElementVO.unmarshall(element);
+				
+				// save reference to display element VO's for tree
+				if (!items) items = new Array();
+				items.push(vo);
+				
+				if ("owner" in element) {
+					element = element.owner as IVisualElement;
+				}
+				
+				ancestors--;
+				
+				if (element==topMostDisplayObject) {
+					ancestors = 0; //bail after the next run through
+				}
+			}
+			
+			return items;
+
+		}
+		
+		/**
+		 * Get the parent of the target that is also a UIComponent
+		 * 
+		 * @return
+		 */
+		public static function getParentUIComponent(target:DisplayObject):UIComponent {
+			var found:Boolean;
+			
+			// run up the display list
+			while (target) {
+				target = target.parent;
+				
+				// check if next parent exists
+				if (!target) {
+					break;
+				}
+				
+				if (target is UIComponent) {
+					found = true;
+					break;
+				}
+				
+			}
+			
+			if (found) return UIComponent(target);
+			return null;
+		}
+		
+		/**
+		 * Get the name of the target parent that is also a UIComponent
+		 * 
+		 * @return
+		 */
+		public static function getParentUIComponentName(target:DisplayObject):String {
+			var parent:DisplayObject = getParentUIComponent(target);
+			var className:String = getClassName(parent);
+			return className;
+		}
+		
+		
+		/**
+		 * Get parent document name
+		 * 
+		 * @return null if target is not a UIComponent
+		 */
+		public static function getParentDocumentName(target:Object):String {
+			var className:String;
+			if (target is UIComponent) {
+				className = getClassName(target.parentDocument);
+			}
+			return className;
+		}
+		
+		
+		/**
+		 * Get parent document name
+		 * 
+		 * @return
+		 */
+		public static function getClassNameAndPackage(target:Object):Array {
+			var className:String;
+			var classPath:String;
+			
+			className = getClassName(target);
+			classPath = getPackageName(target);
+			
+			return [className, classPath];
+		}
+		
+		
+		/**
+		 * Dispatch target change event
+		 * 
+		 * @return
+		 */
+		public static function dispatchTargetChangeEvent(target:Object, source:IEventDispatcher):void {
+			
+			// let other inspectors know there is a new target selected
+			var selectionChangeEvent:InspectorEvent = new InspectorEvent(InspectorEvent.CHANGE);
+			selectionChangeEvent.targetItem = target;
+			
+			// store previous targets in a dictionary
+			
+			if (source) {
+				source.dispatchEvent(selectionChangeEvent);
+			}			
+		}
+		
+		
+		/**
+		 * Change target. Use this instead of dispatchTargetChangeEvent()
+		 * 
+		 * TODO: Add a weak reference to the old target in a static array for history type navigation
+		 * 
+		 * @return
+		 */
+		public static function updateTarget(target:Object, source:IEventDispatcher):void {
+			// TODO: Add a weak reference to the old target in a static array for history type navigation
+			
+			// let other inspectors know there is a new target selected
+			var selectionChangeEvent:InspectorEvent = new InspectorEvent(InspectorEvent.CHANGE);
+			selectionChangeEvent.targetItem = target;
+			
+			if (source) {
+				source.dispatchEvent(selectionChangeEvent);
+			}			
+		}
+		
+		/**
+		 * Converts an integer to hexidecimal. 
+		 * For example, 16117809 returns "#EEEEEE" or something
+		 * @return
+		 */
+		public static function convertIntToHex(item:Object):String {
+			var hex:String = Number(item).toString(16);
+			return ("00000" + hex.toUpperCase()).substr(-6);
+		}
+		
+		
+		/**
+		 * Sets the property on the target. Supports styles. 
+		 * We should probably switch to the set property method 
+		 * @return
+		 */
+		public static function setTargetProperty(target:Object, property:String, value:*, type:String = "String", isPropertyStyle:Object=null):void {
+			var newAssignedValue:* = TypeUtils.getTypedValue(value, type);
+			TypeUtils.applyProperty(target, property, newAssignedValue, type, isPropertyStyle);
+		}
+		
+			
+		/**
+		 * @copy spark.components.gridClasses.GridItemEditor#save();
+		 */
+		public static function setProperty(target:Object, field:String, value:*):Boolean {
+			
+			var newData:Object = value;
+			var property:String = field;
+			var data:Object = target;
+			var typeInfo:String = "";
+			
+			for each(var variable:XML in describeType((data).variable)) {
+				if (property == variable.@name.toString()) {
+					typeInfo = variable.@type.toString();
+					break;
+				}
+			}
+			
+			if (typeInfo == "String") {
+				if (!(newData is String))
+					newData = newData.toString();
+			}
+			else if (typeInfo == "uint") {
+				if (!(newData is uint))
+					newData = uint(newData);
+			}
+			else if (typeInfo == "int") {
+				if (!(newData is int))
+					newData = int(newData);
+			}
+			else if (typeInfo == "Number") {
+				if (!(newData is Number))
+					newData = Number(newData);
+			}
+			else if (typeInfo == "Boolean") {
+				if (!(newData is Boolean)) {
+					var strNewData:String = newData.toString();
+					
+					if (strNewData) {
+						newData = (strNewData.toLowerCase() == "true") ? true : false;
+					}
+				}
+			}
+			
+			if (property && data[property] !== newData) {
+				data[property] = newData;
+			}
+			
+			return true;
+		}
+		
+		/**
+		 *  Returns <code>true</code> if the object reference specified
+		 *  is a simple data type. The simple data types include the following:
+		 *  <ul>
+		 *    <li><code>String</code></li>
+		 *    <li><code>Number</code></li>
+		 *    <li><code>uint</code></li>
+		 *    <li><code>int</code></li>
+		 *    <li><code>Boolean</code></li>
+		 *    <li><code>Date</code></li>
+		 *    <li><code>Array</code></li>
+		 *  </ul>
+		 *
+		 *  @param value Object inspected.
+		 *
+		 *  @return <code>true</code> if the object specified
+		 *  is one of the types above; <code>false</code> otherwise.
+		 *  */
+		public static function isSimple(value:*):Boolean {
+			return ObjectUtil.isSimple(value);
+		}
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-radii8/blob/f370bfcf/Radii8Library/src/com/flexcapacitor/utils/MXMLDocumentExporter.as
----------------------------------------------------------------------
diff --git a/Radii8Library/src/com/flexcapacitor/utils/MXMLDocumentExporter.as b/Radii8Library/src/com/flexcapacitor/utils/MXMLDocumentExporter.as
new file mode 100644
index 0000000..ff3db5f
--- /dev/null
+++ b/Radii8Library/src/com/flexcapacitor/utils/MXMLDocumentExporter.as
@@ -0,0 +1,170 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.utils {
+	import com.flexcapacitor.model.IDocument;
+	import com.flexcapacitor.model.IDocumentExporter;
+	import com.flexcapacitor.utils.supportClasses.ComponentDescription;
+	
+	import spark.components.Application;
+	
+	/**
+	 * Exports a document to MXML
+	 * */
+	public class MXMLDocumentExporter extends DocumentExporter implements IDocumentExporter {
+		
+		public function MXMLDocumentExporter() {
+		
+		}
+		
+		/**
+		 * @inheritDoc
+		 * */
+		public function export(iDocument:IDocument, target:ComponentDescription = null, reference:Boolean = false):* {
+			var output:String;
+			var XML1:XML;
+			
+			if (!target) {
+				target = iDocument.componentDescription;
+			}
+			
+			if (!reference) {
+				output = getMXMLOutputString(iDocument, target);
+			}
+			else {
+				XML1 = <document />;
+				XML1.@host = iDocument.host;
+				XML1.@id = iDocument.id;
+				XML1.@name = iDocument.name;
+				XML1.@uid = iDocument.uid;
+				XML1.@uri = iDocument.uri;
+				output = XML1.toXMLString();
+			}
+			
+			return output;
+		}
+		
+		/**
+		 * @inheritDoc
+		 * */
+		public function exportXML(document:IDocument, reference:Boolean = false):XML {
+			return null;
+		}
+		
+		/**
+		 * @inheritDoc
+		 * */
+		public function exportJSON(document:IDocument, reference:Boolean = false):JSON {
+			return null;
+		}
+		
+	
+		/**
+		 * Gets the formatted MXML output from a component. 
+		 * TODO: This should be using XML and namespaces. 
+		 * */
+		public function getMXMLOutputString(iDocument:IDocument, component:ComponentDescription, addLineBreak:Boolean = false, tabs:String = ""):String {
+			if (component.instance is Application) {
+				getAppliedPropertiesFromHistory(iDocument, component);
+			}
+			var properties:Object = component.properties;
+			var styles:Object = component.styles;
+			var componentChild:ComponentDescription;
+			var name:String = component.name;
+			var output:String = "";
+			var outputValue:String = "";
+			var namespaces:String;
+			var value:*;
+			
+			
+			for (var propertyName:String in properties) {
+				value = properties[propertyName];
+				if (value===undefined || value==null) {
+					continue;
+				}
+				output += " ";
+				
+				// we should be converting objects into tags
+				if (value is Object) {
+					outputValue = XMLUtils.getAttributeSafeString(Object(value).toString());
+					output += propertyName + "=\"" + outputValue + "\"";
+					
+				}
+				else {
+					output += propertyName + "=\"" + XMLUtils.getAttributeSafeString(Object(value).toString()) + "\"";
+				}
+			}
+			
+			for (var styleName:String in styles) {
+				value = styles[styleName];
+				if (value===undefined || value==null) {
+					continue;
+				}
+				output += " ";
+				output += styleName + "=\"" + XMLUtils.getAttributeSafeString(Object(styles[styleName]).toString()) + "\"";
+			}
+			
+			if (name) {
+				if (component.instance is Application) {
+					name = "Application";
+					namespaces = " xmlns:fx=\"http://ns.adobe.com/mxml/2009\"";
+					namespaces += " xmlns:s=\"library://ns.adobe.com/flex/spark\"";
+					output = namespaces + output;
+				}
+				// we are not handling namespaces here - we could use component descriptor
+				output = tabs + "<s:" + name + output;
+				
+				if (component.children && component.children.length>0) {
+					output += ">\n";
+					
+					for (var i:int;i<component.children.length;i++) {
+						componentChild = component.children[i];
+						// we should get the properties and styles from the 
+						// the component description
+						getAppliedPropertiesFromHistory(iDocument, componentChild);
+						output += getMXMLOutputString(iDocument, componentChild, false, tabs + "\t");
+					}
+					
+					output += tabs + "</s:" + name + ">\n";
+				}
+				else {
+					 output += "/>\n";
+				}
+			}
+			else {
+				output = "";
+			}
+			
+			isValid = XMLUtils.isValidXML(output);
+			
+			if (!isValid) {
+				error = XMLUtils.validationError;
+				errorMessage = XMLUtils.validationErrorMessage;
+			}
+			else {
+				error = null;
+				errorMessage = null;
+			}
+			
+			return output;
+		}
+		
+	
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-radii8/blob/f370bfcf/Radii8Library/src/com/flexcapacitor/utils/MXMLDocumentImporter.as
----------------------------------------------------------------------
diff --git a/Radii8Library/src/com/flexcapacitor/utils/MXMLDocumentImporter.as b/Radii8Library/src/com/flexcapacitor/utils/MXMLDocumentImporter.as
new file mode 100644
index 0000000..c48992c
--- /dev/null
+++ b/Radii8Library/src/com/flexcapacitor/utils/MXMLDocumentImporter.as
@@ -0,0 +1,143 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.utils {
+	
+	import com.flexcapacitor.controller.Radiate;
+	import com.flexcapacitor.model.IDocument;
+	import com.flexcapacitor.utils.supportClasses.ComponentDefinition;
+	
+	import flash.events.EventDispatcher;
+	import flash.system.ApplicationDomain;
+	import flash.utils.getTimer;
+	
+	import mx.core.IVisualElement;
+
+	
+	/**
+	 * Import MXML into a IDocument. Basic support of creating components and apply properties and styles. 
+	 * */
+	public class MXMLDocumentImporter extends EventDispatcher {
+	
+		public var document:IDocument;
+
+		/**
+		 * Import the MXML document into the IDocument. 
+		 * */
+		public function MXMLDocumentImporter(iDocument:IDocument, id:String, mxml:XML, container:IVisualElement) {
+			document = iDocument;
+			
+			var elName:String = mxml.localName();
+			var timer:int = getTimer(); 
+			
+			Radiate.importingDocument = true;
+			
+			// TODO this is a special case we check for since 
+			// we should have already created the application by now
+			// we should handle this case before we get here (pass in the children of the application xml not application itself)
+			if (elName=="Application") {
+				Radiate.setAttributesOnComponent(document.instance, mxml);
+			}
+			else {
+				createChildFromNode(mxml, container);
+			}
+			
+			
+			for each (var childNode:XML in mxml.children()) {
+				createChildFromNode(childNode, container);
+			}
+			
+			Radiate.importingDocument = false;
+			
+			// using importing document flag it goes down from 5 seconds to 1 second
+			//Radiate.log.info("Time to import: " + (getTimer()-timer));
+			
+		}
+
+		/**
+		 * Create child from node
+		 * */
+		private function createChildFromNode(node:XML, parent:Object):IVisualElement {
+			var elementName:String = node.localName();
+			var domain:ApplicationDomain = ApplicationDomain.currentDomain;
+			var componentDefinition:ComponentDefinition = Radiate.getDynamicComponentType(elementName);
+			var className:String;
+			var classType:Class;
+			var includeChildren:Boolean = true;
+			var instance:Object;
+			
+			if (componentDefinition==null) {
+				
+			}
+			
+			className =componentDefinition ? componentDefinition.className :null;
+			classType = componentDefinition ? componentDefinition.classType as Class :null;
+			
+			
+			if (componentDefinition==null && elementName!="RootWrapperNode") {
+				//message += " Add this class to Radii8LibrarySparkAssets.sparkManifestDefaults or add the library to the project that contains it.";
+				var message:String = "Could not find definition for " + elementName + ". The document will be missing elements.";
+				Radiate.log.error(message);
+				return null;
+			}
+			
+			// classes to look into for decoding XML
+			// XMLDecoder, SchemaTypeRegistry, SchemaManager, SchemaProcesser
+			
+			
+			// special case for radio button group
+			/*var object:* = SchemaTypeRegistry.getInstance().getClass(classType);
+			var object2:* = SchemaTypeRegistry.getInstance().getClass(elementName);
+			var object3:* = SchemaTypeRegistry.getInstance().getClass(node);
+			var sm:mx.rpc.xml.SchemaManager = new mx.rpc.xml.SchemaManager();
+			
+			sm.addNamespaces({s:new Namespace("s", "library://ns.adobe.com/flex/spark")});
+			var o:Object = sm.unmarshall(node);
+			
+			var q:QName = new QName(null, elementName);*/
+			//var object2:* = SchemaTypeRegistry.getInstance().registerClass(;
+			
+	
+			if (componentDefinition!=null) {
+				instance = Radiate.createComponentForAdd(document, componentDefinition, true);
+				//Radiate.log.info("MXML Importer adding: " + elementName);
+				
+				// calling add before setting properties because some 
+				// properties such as borderVisible need to be set after 
+				// the component is added (maybe)
+				Radiate.addElement(instance, parent);
+				
+				Radiate.setAttributesOnComponent(instance, node);
+				
+			}
+			
+			
+			if (includeChildren) {
+				
+				for each (var childNode:XML in node.children()) {
+					createChildFromNode(childNode, instance);
+				}
+			}
+			
+			return instance as IVisualElement;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/flex-radii8/blob/f370bfcf/Radii8Library/src/com/flexcapacitor/utils/MXMLImporterEvent.as
----------------------------------------------------------------------
diff --git a/Radii8Library/src/com/flexcapacitor/utils/MXMLImporterEvent.as b/Radii8Library/src/com/flexcapacitor/utils/MXMLImporterEvent.as
new file mode 100644
index 0000000..e4cdc02
--- /dev/null
+++ b/Radii8Library/src/com/flexcapacitor/utils/MXMLImporterEvent.as
@@ -0,0 +1,37 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.utils
+{
+	import flash.events.Event;
+	
+
+	public class MXMLImporterEvent extends Event 
+	{
+		
+		public static var INITIALIZE:String = "onInitialize";
+		public var idString : String;
+
+		public function MXMLImporterEvent(type : String, indata:String, bubbles : Boolean = false, cancelable : Boolean = false)
+		{
+			super( type, bubbles, cancelable );
+			idString = indata;
+		}
+	}	
+
+}
\ No newline at end of file