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

[18/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/AndroidDocumentExporter.as
----------------------------------------------------------------------
diff --git a/Radii8Library/src/com/flexcapacitor/utils/AndroidDocumentExporter.as b/Radii8Library/src/com/flexcapacitor/utils/AndroidDocumentExporter.as
new file mode 100644
index 0000000..1b8df8c
--- /dev/null
+++ b/Radii8Library/src/com/flexcapacitor/utils/AndroidDocumentExporter.as
@@ -0,0 +1,518 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 mx.core.IVisualElement;
+	
+	import spark.components.supportClasses.GroupBase;
+	import spark.layouts.HorizontalLayout;
+	import spark.layouts.VerticalLayout;
+	
+	/**
+	 * Exports a document to Android markup
+	 * */
+	public class AndroidDocumentExporter extends DocumentExporter {
+		
+		public function AndroidDocumentExporter() {
+		
+		}
+		
+		/**
+		 * Last source code
+		 * */
+		[Bindable]
+		public var sourceCode:String;
+		
+		public var includePreviewCode:Boolean;
+		
+		public var horizontalPositions:Array = ["x","left","right","horizontalCenter"];
+		public var verticalPositions:Array = ["y","top","bottom","verticalCenter"];
+		public var sizesPositions:Array = ["width","height"];
+		
+		
+		/**
+		 * @inheritDoc
+		 * */
+		public function exportXMLString(iDocument:IDocument, reference:Boolean = false, target:Object = null):String {
+			var XML1:XML;
+			//document = iDocument;
+			var application:Object = iDocument ? iDocument.instance : null;
+			var targetDescription:ComponentDescription;
+			var componentTree:ComponentDescription;
+			var output:String = "";
+			var xml:XML;
+			
+			componentTree = iDocument.componentDescription;
+			
+			
+			// 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 = getAndroidOutputString(document.componentDescription);
+					
+					var includePreviewCode:Boolean = true;
+					
+					output = getAndroidOutputString(iDocument, targetDescription, true, "", includePreviewCode);
+					output = output + "\n";
+						
+					try {
+						// don't use XML for Android output because it converts this:
+						// <div ></div>
+						// to this:
+						// <div />
+						// and that breaks the Android page
+						
+						// we can still try it to make sure it's valid
+						xml = new XML(output); // check if valid
+						
+						sourceCode = output;
+						// passing the raw string not the xml
+						//setTextareaCode(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>
+						sourceCode = output;
+						//setTextareaCode(output);
+					}
+				}
+				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;
+		}
+	
+
+		/**
+		 * Gets the formatted output from a component.
+		 * Needs refactoring.
+		 * */
+		public function getAndroidOutputString(iDocument:IDocument, component:ComponentDescription, addLineBreak:Boolean = false, tabs:String = "", includePreview:Boolean = false):String {
+			var property:Object = component.properties;
+			var name:String = component.name.toLowerCase();
+			var componentChild:ComponentDescription;
+			var styles:String = "position:absolute;";
+			var contentToken:String = "[child_content]";
+			var isHorizontalLayout:Boolean;
+			var isVerticalLayout:Boolean;
+			var childContent:String = "";
+			var wrapperTag:String = "";
+			var wrapperTagStyles:String = "";
+			var properties:String = "";
+			var output:String = "";
+			var type:String = "";
+			var value:*;
+			var index:int;
+			var numElements:int;
+			var gap:int;
+			
+			// get layout positioning
+			if (component.parent && component.parent.instance is GroupBase) {
+				
+				if (component.parent.instance.layout is HorizontalLayout) {
+					isHorizontalLayout = true;
+					index = GroupBase(component.parent.instance).getElementIndex(component.instance as IVisualElement);
+					numElements = GroupBase(component.parent.instance).numElements;
+					wrapperTagStyles += "display:inline;";
+					gap = HorizontalLayout(component.parent.instance.layout).gap - 4;
+					
+					if (index<numElements-1 && numElements>1) {
+						wrapperTagStyles += "padding-right:" + gap + "px";
+					}
+					
+					wrapperTag = "div";
+				}
+				
+				else if (component.parent.instance.layout is VerticalLayout) {
+					isVerticalLayout = true;
+					styles = styles.replace("absolute", "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";
+					}
+					
+					wrapperTag = "div";
+				}
+			}
+			
+			
+			// loop through assigned properties
+			for (var propertyName:String in property) {
+				value = property[propertyName];
+				
+				if (value===undefined || value==null) {
+					continue;
+				}
+				
+				
+				// if horizontal or vertical layout do not add position
+				if (propertyName=="x" || propertyName=="left") {
+					
+					if (!isHorizontalLayout && !isVerticalLayout) {
+						styles += "left:" +  Object(property[propertyName]).toString() + "px;";
+					}
+				}
+				else if (propertyName=="y" || propertyName=="top") {
+					
+					if (!isHorizontalLayout && !isVerticalLayout) {
+						styles += "top:" +  Object(property[propertyName]).toString() + "px;";
+					}
+				}
+				else {
+					properties += propertyName + "=\"" + Object(property[propertyName]).toString() + "\"";
+					properties += " ";
+				}
+			}
+			
+			
+			if (name) {
+				
+				// create code for element type
+				if (name=="application") {
+					name = "merge";
+					output += "<merge";
+					output += " xmlns:android=\"http://schemas.android.com/apk/res/android\"";
+					output += " xmlns:tools=\"http://schemas.android.com/tools\"";
+					output += ">";
+					output += contentToken;
+					output += "\n</merge>";
+					
+					// container div
+					if (includePreview) {
+						
+					}
+					else {
+					}
+				}
+				
+				else if (name=="group") {
+					name = "RelativeLayout";
+					output = tabs + "<RelativeLayout";
+					output += " android:layout_width=\"" + getAndroidEquivalentSize(component.instance as IVisualElement) + "\"";
+					output += " android:layout_height=\"" + getAndroidEquivalentSize(component.instance as IVisualElement, false) + "\"";
+					output += ">";
+					output += contentToken;
+					output += "\n" + tabs + "</RelativeLayout>";
+				}
+				
+				
+				else if (name=="vgroup" || name=="hgroup") {
+					output = tabs + "<LinearLayout";
+					
+					if (name=="hgroup") {
+						output += " android:orientation=\"horizontal\"";
+					}
+					else {
+						output += " android:orientation=\"vertical\"";
+					}
+					name = "LinearLayout";
+					
+					output += " android:layout_width=\"" + getAndroidEquivalentSize(component.instance as IVisualElement) + "\"";
+					output += " android:layout_height=\"" + getAndroidEquivalentSize(component.instance as IVisualElement, false) + "\"";
+					output += ">";
+					output += contentToken;
+					output += "\n" + tabs + "</LinearLayout>";
+				}
+				
+				else if (name=="button") {
+					/*<Button android:id="@+id/sign_in_button"
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content"
+	                android:layout_marginTop="16dp"
+	                android:text="@string/action_sign_in_register"
+	                android:paddingLeft="32dp"
+	                android:paddingRight="32dp"
+	                android:layout_gravity="right" />*/
+					output = tabs;
+					output += "<Button";
+					output += " android:layout_width=\"" + getAndroidEquivalentSize(component.instance as IVisualElement) + "\"";
+					output += " android:layout_height=\"" + getAndroidEquivalentSize(component.instance as IVisualElement, false) + "\"";
+					
+					/*if (component.parent.name=="group") {
+						output += " android:layout_marginLeft=\"" + getAndroidEquivalentPosition(component) + "\"";
+						output += " android:layout_marginTop=\"" + getAndroidEquivalentPosition(component, false) + "\"";
+					}
+					else {
+						
+					}*/
+					
+					output += " android:text=\"" + component.instance.label + "\"";
+					output += "/>";
+				}
+				else if (name=="checkbox") {
+					name = "CheckBox";
+					output = tabs;
+					output += "<CheckBox";
+					output += " android:layout_width=\"" + getAndroidEquivalentSize(component.instance as IVisualElement) + "\"";
+					output += " android:layout_height=\"" + getAndroidEquivalentSize(component.instance as IVisualElement, false) + "\"";
+					output += " android:text=\"" + component.instance.label + "\"/>";
+					
+					//output += getWrapperTag(wrapperTag, true);
+				}
+				else if (name=="textinput") {
+					/*				
+			            <EditText
+			                android:id="@+id/password"
+			                android:singleLine="true"
+			                android:maxLines="1"
+			                android:layout_width="match_parent"
+			                android:layout_height="wrap_content"
+			                android:hint="@string/prompt_password"
+			                android:inputType="textPassword"
+			                android:imeActionLabel="@string/action_sign_in_short"
+			                android:imeActionId="@+id/login"
+			                android:imeOptions="actionUnspecified" />*/
+					name = "EditText";
+					output = tabs;
+					output += "<EditText";
+					output += " android:layout_width=\"" + getAndroidEquivalentSize(component.instance as IVisualElement) + "\"";
+					output += " android:layout_height=\"" + getAndroidEquivalentSize(component.instance as IVisualElement, false) + "\"";
+					output += " android:singleLine=\"true\"";
+					output += " android:maxLines=\"1\"";
+					output += " android:fontFamily=\"" + component.instance.inheritingStyles.fontFamily + "\"";
+					output += " android:hint=\""+ component.instance.prompt +"\"";
+					
+					if (component.instance.displayAsPassword) {
+						output += " android:inputType=\"textPassword\"";
+					}
+					else {
+						output += " android:inputType=\"text\"";
+					}
+					
+					output += "/>";
+				}
+				else if (name=="label") {
+					/* <TextView
+		            android:id="@+id/login_status_message"
+		            android:textAppearance="?android:attr/textAppearanceMedium"
+		            android:fontFamily="sans-serif-light"
+		            android:layout_width="wrap_content"
+		            android:layout_height="wrap_content"
+		            android:layout_marginBottom="16dp"
+		            android:text="@string/login_progress_signing_in" />*/
+					name = "TextView";
+					output = tabs;
+					output += "<TextView";
+					output += " android:layout_width=\"" + getAndroidEquivalentSize(component.instance as IVisualElement) + "\"";
+					output += " android:layout_height=\"" + getAndroidEquivalentSize(component.instance as IVisualElement, false) + "\"";
+					output += " android:fontFamily=\"" + component.instance.inheritingStyles.fontFamily + "\"";
+					output += " android:text=\""+ component.instance.text+"\"";
+					output += "/>";
+				}
+				else if (name=="image") {
+					name = "ImageView";
+					output = tabs;
+					output += "<ImageView " + properties;
+					output += " android:layout_width=\"" + getAndroidEquivalentSize(component.instance as IVisualElement) + "\"";
+					output += " android:layout_height=\"" + getAndroidEquivalentSize(component.instance as IVisualElement, false) + "\"";
+					output += " android:src=\"@drawable/" + component.instance.source + "\"";
+					output += "/>";
+				}
+				
+				else {
+					output = tabs;
+					output += "<!--<" + name.toLowerCase()  + " " + properties;
+					output += properties ? " " : "";
+					output += "style=\"" + styles + "\"/>-->";
+					//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 += getAndroidOutputString(iDocument, componentChild, false, tabs + "\t");
+					}
+					
+					output = output.replace(contentToken, "\n" + childContent);
+
+				}
+				else {
+					output = output.replace(contentToken, "\n");
+				}
+			}
+			else {
+				output = "";
+			}
+			
+			return output;
+		}
+		
+		/**
+		 * Get Android equivalent size. 
+		 * Android has fill_parent, match_parent and wrap_content.
+		 * It also has numeric value, like "55dp".
+		 * */
+		public function getAndroidEquivalentSize(element:IVisualElement, width:Boolean = true):String {
+			var isPercent:Boolean;
+			var output:String;
+			
+			// get width
+			if (width) {
+				isPercent = Boolean(element.percentWidth);
+				
+				if (isPercent) {
+					if (element.percentWidth==100) {
+						output = "fill_parent";
+					}
+					else {
+						output = String(element.width) + "dp"; // absolute value
+					}
+				}
+				else {
+					if ("explicitWidth" in element && element.width==Object(element).explicitWidth) {
+						output = String(element.width) + "dp";
+					}
+					else {
+						output = "wrap_content";
+					}
+				}
+				
+				return output;
+			}
+			
+			// get height
+			isPercent = Boolean(element.percentHeight);
+			
+			
+			if (isPercent) {
+				if (element.percentHeight==100) {
+					output = "fill_parent";
+				}
+				else {
+					output = String(element.height) + "dp"; // absolute value
+				}
+			}
+			else {
+				if ("explicitHeight" in element && element.height==Object(element).percentHeight) {
+					output = String(element.height) + "dp";
+				}
+				else {
+					output = "wrap_content";
+				}
+			}
+			
+			return output;
+		}
+		
+		/**
+		 * Get Android equivalent position
+		 * */
+		public function getAndroidEquivalentPosition(componentDescription:ComponentDescription, x:Boolean = true):String {
+			var element:Object = componentDescription.instance;
+			var isPercent:Boolean;
+			var output:String;
+			
+			// get width
+			if (x) {
+				isPercent = Boolean(element.percentWidth);
+				
+				
+				if (isPercent) {
+					if (element.percentWidth==100) {
+						output = "fill_parent";
+					}
+					else {
+						output = String(element.width) + "dp"; // absolute value
+					}
+				}
+				else {
+					if ("explicitWidth" in element && element.width==Object(element).explicitWidth) {
+						output = String(element.width) + "dp";
+					}
+					else {
+						output = "wrap_content";
+					}
+				}
+				
+				return output;
+			}
+			
+			// get height
+			isPercent = Boolean(element.percentHeight);
+			
+			
+			if (isPercent) {
+				if (element.percentHeight==100) {
+					output = "fill_parent";
+				}
+				else {
+					output = String(element.height) + "dp"; // absolute value
+				}
+			}
+			else {
+				if ("explicitHeight" in element && element.height==Object(element).percentHeight) {
+					output = String(element.height) + "dp";
+				}
+				else {
+					output = "wrap_content";
+				}
+			}
+			
+			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;
+		}
+		
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-radii8/blob/f370bfcf/Radii8Library/src/com/flexcapacitor/utils/Base64.as
----------------------------------------------------------------------
diff --git a/Radii8Library/src/com/flexcapacitor/utils/Base64.as b/Radii8Library/src/com/flexcapacitor/utils/Base64.as
new file mode 100644
index 0000000..a84372c
--- /dev/null
+++ b/Radii8Library/src/com/flexcapacitor/utils/Base64.as
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2012 Jean-Philippe Auclair
+ * Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+ * Base64 library for ActionScript 3.0.
+ * By: Jean-Philippe Auclair : http://jpauclair.net
+ * Based on article: http://jpauclair.net/2010/01/09/base64-optimized-as3-lib/
+ * Benchmark:
+ * This version: encode: 260ms decode: 255ms
+ * Blog version: encode: 322ms decode: 694ms
+ * as3Crypto encode: 6728ms decode: 4098ms
+ *
+ * Encode: com.sociodox.utils.Base64 is 25.8x faster than as3Crypto Base64
+ * Decode: com.sociodox.utils.Base64 is 16x faster than as3Crypto Base64
+ *
+ * Optimize & Profile any Flash content with TheMiner ( http://www.sociodox.com/theminer )
+ */
+package com.flexcapacitor.utils {
+	
+	import flash.utils.ByteArray;
+	
+	public class Base64
+	{
+		private static const _encodeChars:Vector.<int> = InitEncoreChar();
+		private static const _decodeChars:Vector.<int> = InitDecodeChar();
+		
+		public static function encode(data:ByteArray):String
+		{
+			var out:ByteArray = new ByteArray();
+			//Presetting the length keep the memory smaller and optimize speed since there is no "grow" needed
+			out.length = (2 + data.length - ((data.length + 2) % 3)) * 4 / 3; //Preset length //1.6 to 1.5 ms
+			var i:int = 0;
+			var r:int = data.length % 3;
+			var len:int = data.length - r;
+			var c:uint; //read (3) character AND write (4) characters
+			var outPos:int = 0;
+			while (i < len)
+			{
+				//Read 3 Characters (8bit * 3 = 24 bits)
+				c = data[int(i++)] << 16 | data[int(i++)] << 8 | data[int(i++)];
+				
+				out[int(outPos++)] = _encodeChars[int(c >>> 18)];
+				out[int(outPos++)] = _encodeChars[int(c >>> 12 & 0x3f)];
+				out[int(outPos++)] = _encodeChars[int(c >>> 6 & 0x3f)];
+				out[int(outPos++)] = _encodeChars[int(c & 0x3f)];
+			}
+			
+			if (r == 1) //Need two "=" padding
+			{
+				//Read one char, write two chars, write padding
+				c = data[int(i)];
+				
+				out[int(outPos++)] = _encodeChars[int(c >>> 2)];
+				out[int(outPos++)] = _encodeChars[int((c & 0x03) << 4)];
+				out[int(outPos++)] = 61;
+				out[int(outPos++)] = 61;
+			}
+			else if (r == 2) //Need one "=" padding
+			{
+				c = data[int(i++)] << 8 | data[int(i)];
+				
+				out[int(outPos++)] = _encodeChars[int(c >>> 10)];
+				out[int(outPos++)] = _encodeChars[int(c >>> 4 & 0x3f)];
+				out[int(outPos++)] = _encodeChars[int((c & 0x0f) << 2)];
+				out[int(outPos++)] = 61;
+			}
+			
+			return out.readUTFBytes(out.length);
+		}
+		
+		public static function decode(str:String):ByteArray
+		{
+			var c1:int;
+			var c2:int;
+			var c3:int;
+			var c4:int;
+			var i:int = 0;
+			var len:int = str.length;
+			
+			var byteString:ByteArray = new ByteArray();
+			byteString.writeUTFBytes(str);
+			var outPos:int = 0;
+			while (i < len)
+			{
+				//c1
+				c1 = _decodeChars[int(byteString[i++])];
+				if (c1 == -1)
+					break;
+				
+				//c2
+				c2 = _decodeChars[int(byteString[i++])];
+				if (c2 == -1)
+					break;
+				
+				byteString[int(outPos++)] = (c1 << 2) | ((c2 & 0x30) >> 4);
+				
+				//c3
+				c3 = byteString[int(i++)];
+				if (c3 == 61)
+				{
+					byteString.length = outPos
+					return byteString;
+				}
+				
+				c3 = _decodeChars[int(c3)];
+				if (c3 == -1)
+					break;
+				
+				byteString[int(outPos++)] = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2);
+				
+				//c4
+				c4 = byteString[int(i++)];
+				if (c4 == 61)
+				{
+					byteString.length = outPos
+					return byteString;
+				}
+				
+				c4 = _decodeChars[int(c4)];
+				if (c4 == -1)
+					break;
+				
+				byteString[int(outPos++)] = ((c3 & 0x03) << 6) | c4;
+			}
+			byteString.length = outPos
+			return byteString;
+		}
+		
+		public static function InitEncoreChar():Vector.<int>
+		{
+			var encodeChars:Vector.<int> = new Vector.<int>(64, true);
+			
+			// We could push the number directly
+			// but I think it's nice to see the characters (with no overhead on encode/decode)
+			var chars:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+			for (var i:int = 0; i < 64; i++)
+			{
+				encodeChars[i] = chars.charCodeAt(i);
+			}
+			
+			return encodeChars;
+		}
+		
+		public static function InitDecodeChar():Vector.<int>
+		{
+			
+			var decodeChars:Vector.<int> = new <int>[
+				-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+				-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+				-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 
+				52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, 
+				-1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 
+				15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, 
+				-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 
+				41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, 
+				-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+				-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+				-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+				-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+				-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+				-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+				-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+				-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1];
+			
+			return decodeChars;
+		}
+	
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-radii8/blob/f370bfcf/Radii8Library/src/com/flexcapacitor/utils/ClassUtils.as
----------------------------------------------------------------------
diff --git a/Radii8Library/src/com/flexcapacitor/utils/ClassUtils.as b/Radii8Library/src/com/flexcapacitor/utils/ClassUtils.as
new file mode 100644
index 0000000..b3d7b8c
--- /dev/null
+++ b/Radii8Library/src/com/flexcapacitor/utils/ClassUtils.as
@@ -0,0 +1,716 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.events.InspectorEvent;
+	import com.flexcapacitor.graphics.LayoutLines;
+	import com.flexcapacitor.model.AccessorMetaData;
+	import com.flexcapacitor.model.MetaData;
+	import com.flexcapacitor.model.StyleMetaData;
+	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.collections.XMLListCollection;
+	import mx.core.IVisualElement;
+	import mx.core.IVisualElementContainer;
+	import mx.core.UIComponent;
+	import mx.managers.ISystemManager;
+	import mx.utils.DescribeTypeCache;
+	import mx.utils.DescribeTypeCacheRecord;
+	import mx.utils.NameUtil;
+	import mx.utils.ObjectUtil;
+	
+	import avmplus.DescribeType;
+
+	public class ClassUtils {
+
+
+		public function ClassUtils() {
+
+
+		}
+		
+		/**
+		 * @copy NameUtil.getUnqualifiedClassName()
+		 * */
+		public static function getClassName(element:Object):String {
+			var name:String = NameUtil.getUnqualifiedClassName(element);
+			return name;
+		}
+		
+		/**
+		 * Get unqualified class name of the target object. <br/>
+		 * 
+		 * If target has the id of myImage and include class name is true then the result is
+		 * "Image.myImage". If delimiter is "_" then the result is "Image_myImage". 
+		 * If includeClassName is false then the result is, "myImage". 
+		 * */
+		public static function getClassNameOrID(element:Object, includeClassName:Boolean = false, delimiter:String = "."):String {
+			var name:String = NameUtil.getUnqualifiedClassName(element);
+			var id:String = element && "id" in element ? element.id : null;
+			
+			return !id ? name : includeClassName ? name + "." + id : id;
+		}
+		
+		/**
+		 * 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 fully qualified package of an object minus the class name. 
+		 * 
+		 * For example, if fully qualified class name is "mx.components::Button" then
+		 * this method returns "mx.components".
+		 * */
+		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;
+		}
+
+
+		/**
+		 * Gets the ID of the target object
+		 * 
+		 * @param name if id is not available then if true then use name
+		 * @param className if id is not available then if true use class name
+		 * 
+		 * returns id or name or class name or null if no ID is specified
+		 * */
+		public static function getIdentifierOrName(element:Object, name:Boolean = false, className:Boolean = false):String {
+
+			if (element && "id" in element && element.id) {
+				return element.id;
+			}
+			else if (element && name && "name" in element && element.name) {
+				return element.name;
+			}
+			else if (element && className) {
+				return getClassName(element);
+			}
+			
+			return null;
+		}
+
+		/**
+		 * 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. 
+		 * If normalize is true then replaces, "::" with ".";
+		 * 
+		 * @copy flash.utils.getQualifiedClassName()
+		 * */
+		public static function getQualifiedClassName(element:Object, normalize:Boolean = false):String {
+			var name:String = flash.utils.getQualifiedClassName(element);
+			if (normalize && name) {
+				name = name.replace("::", ".");
+			}
+			return name;
+		}
+
+		/**
+		 * Checks if the source object is the same type as the target object. 
+		 * */
+		public static function isSameClassType(source:Object, target:Object):Boolean {
+			if (source==null && target!=null) {
+				return false;
+			}
+			if (target==null && source!=null) {
+				return false;
+			}
+			
+			if (flash.utils.getQualifiedClassName(source) == flash.utils.getQualifiedClassName(target)) {
+				return true;
+			}
+			
+			return false;
+		}
+
+		/**
+		 * 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 = getIdentifierOrName(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;
+		}
+
+		
+		/**
+		 * 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 {
+			LayoutLines.getInstance().drawLines(target, systemManager);
+		}
+
+		/**
+		 * 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;
+		}
+
+		/**
+		 * Get ancestors of target 
+		 * 
+		 * @param target
+		 * @param collection
+		 * @param ancestors
+		 * @return
+		 */
+		public static function getVisualElementsArray(target:DisplayObject, collection:Array, ancestors:int = 0):Array {
+			var vo:VisualElementVO;
+
+
+			// do the worm up the display list
+			while (target && ancestors>-1) {
+
+				// store display element information
+				vo = VisualElementVO.unmarshall(target);
+
+				// save reference to display element VO's for tree
+				if (!collection) collection = new Array();
+				collection.push(vo);
+
+				target = target.parent;
+				ancestors--;
+
+			}
+
+			return collection;
+		}
+		
+		/**
+		 * 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);
+		}
+		
+		/**
+		 * Get describeType data for the given class. 
+		 * Can take string, instance or class. 
+		 * */
+		public static function getDescribeType(object:Object):XML {
+			var describedTypeRecord:mx.utils.DescribeTypeCacheRecord = mx.utils.DescribeTypeCache.describeType(object);
+			
+			return describedTypeRecord.typeDescription;
+		}
+		
+		/**
+		 * Get AccessorMetaData data for the given property. 
+		 * */
+		public static function getMetaDataOfProperty(target:Object, property:String):AccessorMetaData {
+			var describedTypeRecord:mx.utils.DescribeTypeCacheRecord = mx.utils.DescribeTypeCache.describeType(target);
+			var accessorMetaData:AccessorMetaData = new AccessorMetaData();
+			var matches:XMLList = describedTypeRecord.typeDescription.accessor.(@name==property);
+			var node:XML;
+			
+			if (matches.length()>0) {
+				node = matches[0];
+				accessorMetaData.unmarshall(node, target);
+				return accessorMetaData;
+			}
+			
+			return null;
+		}
+		
+		/**
+		 * Get StyleMetaData data for the given style. 
+		 * */
+		public static function getMetaDataOfStyle(target:Object, style:String, superType:String = null):StyleMetaData {
+			var describedTypeRecord:mx.utils.DescribeTypeCacheRecord;
+			var matches:XMLList;
+			var styleMetaData:StyleMetaData;
+			var extendsClassList:XMLList;
+			var node:XML;
+			
+			if (superType) {
+				describedTypeRecord = mx.utils.DescribeTypeCache.describeType(superType);
+			}
+			else {
+				describedTypeRecord = mx.utils.DescribeTypeCache.describeType(target);
+			}
+			
+			if (superType || target is String) {
+				matches = describedTypeRecord.typeDescription.factory.metadata.(@name=="Style").arg.(@value==style);
+			}
+			else if (target is Object) {
+				matches = describedTypeRecord.typeDescription.metadata.(@name=="Style").arg.(@value==style);
+			}
+			
+			if (matches && matches.length()==0) {
+				
+				if (superType || target is String) {
+					extendsClassList = describedTypeRecord.typeDescription.factory.extendsClass;
+				}
+				else if (target is Object) {
+					extendsClassList = describedTypeRecord.typeDescription.extendsClass;
+				}
+				
+				var length:int = extendsClassList.length();
+				
+				for (var i:int;i<length;i++) {
+					var type:String = extendsClassList[i].@type;
+					if (type=="Class") return null;
+					return getMetaDataOfStyle(target, style, type);
+				}
+				
+			}
+			
+			if (matches.length()>0) {
+				node = matches[0].parent();
+				styleMetaData = new StyleMetaData();
+				styleMetaData.unmarshall(node, target);
+				return styleMetaData;
+			}
+			
+			return null;
+		}
+		
+		/**
+		 * Creates an array of metadata items for the given object type including inherited metadata. 
+		 * 
+		 * For example, if you give it a Spark Button class it gets all the
+		 * information for it and then gets it's super class ButtonBase and 
+		 * adds all that information and so on until it gets to Object. <br/><br/>
+		 * 
+		 * Usage:<br/><pre>
+		 * var allStyles:XMLList = concatenateMetaDataXMLItems(myButton, "Style", new XMLList());
+		 * </pre>
+		 * @param metaType The name of the data in the item name property. Either Style or Event
+		 * @param existingItems The list of the data in the item name property
+		 * */
+		public static function concatenateMetaDataXMLItems(object:Object, metaType:String, existingItems:XMLList = null):XMLList {
+			var describedTypeRecord:mx.utils.DescribeTypeCacheRecord = mx.utils.DescribeTypeCache.describeType(object);
+			var typeDescription:* = describedTypeRecord.typeDescription;
+			var hasFactory:Boolean = typeDescription.factory.length()>0;
+			var factory:* = typeDescription.factory;
+			var extendsClass:XMLList = typeDescription.extendsClass;
+			var extendsLength:int = extendsClass.length();
+			var list:XMLListCollection = new XMLListCollection(typeDescription.*);
+			// can be on typeDescription.metadata or factory.metadata
+			var isRoot:Boolean = object is String ? false : true;
+			var className:String = !isRoot ? object as String : getQualifiedClassName(object);
+			var itemsLength:int;
+			var itemsList:XMLList;
+			var existingItemsLength:int = existingItems ? existingItems.length() : 0;
+			var metaName:String;
+			var duplicateItems:Array = [];
+			
+			if (metaType.toLowerCase()=="style") {
+				metaType = "Style"; 
+			}
+			else if (metaType.toLowerCase()=="event") {
+				metaType = "Event"; 
+			}
+			
+			if (hasFactory) {
+				//itemsList = factory.metadata.(@name==name); property "name" won't work! no matches found
+				itemsList = factory.metadata.(@name==metaType);
+			}
+			else {
+				itemsList = typeDescription.metadata.(@name==metaType);
+			}
+			
+			itemsList = itemsList.copy();
+			itemsLength = itemsList.length();
+			
+			//trace("getting info on class : " + className + " for data on " + nAmEe );
+			//trace(" items : " + itemsList);
+			
+			
+			for (var i:int;i<itemsLength;i++) {
+				var item:XML = XML(itemsList[i]);
+				metaName = item.arg[0].@value;
+				item.@name = metaName;
+				item.@metadataType = metaType;
+				item.@declaredBy = className;
+				//item.@className = className.indexOf("::")!=-1 ? className.split("::")[1] : className;
+				//continue;
+				
+				for (var j:int=0;j<existingItemsLength;j++) {
+					var existingItem:XML = existingItems[j];
+					
+					if (metaName==existingItem.@name) {
+						delete itemsList[i];
+						itemsLength--;
+						i--;
+						//trace("meta name: " + metaName);
+						//trace("Deleting style: " + existingItem.@name);
+						continue;
+					}
+				}
+			}
+			
+			
+			if (itemsLength>0) {
+				existingItems = new XMLList(existingItems.toString()+itemsList.toString());
+			}
+
+			if (isRoot && extendsLength>0) {
+				for (i=0;i<extendsLength;i++) {
+					var newClass:String = String(extendsClass[i].@type);
+					existingItems = concatenateMetaDataXMLItems(newClass, metaType, existingItems);
+				}
+			}
+			
+			return existingItems;
+		}
+		
+		
+		/**
+		 * 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/DocumentExporter.as
----------------------------------------------------------------------
diff --git a/Radii8Library/src/com/flexcapacitor/utils/DocumentExporter.as b/Radii8Library/src/com/flexcapacitor/utils/DocumentExporter.as
new file mode 100644
index 0000000..381a2ce
--- /dev/null
+++ b/Radii8Library/src/com/flexcapacitor/utils/DocumentExporter.as
@@ -0,0 +1,199 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.events.HistoryEvent;
+	import com.flexcapacitor.events.HistoryEventItem;
+	import com.flexcapacitor.model.IDocument;
+	import com.flexcapacitor.utils.supportClasses.ComponentDescription;
+	
+	import mx.collections.ArrayCollection;
+	
+	/**
+	 * Exports document 
+	 * */
+	public class DocumentExporter {
+		
+		/**
+		 * Constructor
+		 * */
+		public function DocumentExporter() {
+			
+		}
+		
+		private var _isValid:Boolean;
+
+		/**
+		 * Indicates if the XML validation
+		 * */
+		[Bindable]
+		public function get isValid():Boolean {
+			return _isValid;
+		}
+
+		/**
+		 * @private
+		 */
+		public function set isValid(value:Boolean):void {
+			_isValid = value;
+		}
+
+		
+		private var _error:Error;
+
+		/**
+		 * Validation error
+		 * */
+		[Bindable]
+		public function get error():Error {
+			return _error;
+		}
+
+		/**
+		 * @private
+		 */
+		public function set error(value:Error):void {
+			_error = value;
+		}
+
+		
+		private var _errorMessage:String;
+
+		/**
+		 * Validation error message
+		 * */
+		[Bindable]
+		public function get errorMessage():String {
+			return _errorMessage;
+		}
+
+		/**
+		 * @private
+		 */
+		public function set errorMessage(value:String):void {
+			_errorMessage = value;
+		}
+
+		
+		private var _errors:Array = [];
+		
+		/**
+		 * Error messages
+		 * */
+		[Bindable]
+		public function get errors():Array {
+			return _errors;
+		}
+
+		/**
+		 * @private
+		 */
+		public function set errors(value:Array):void {
+			_errors = value;
+		}
+
+		private var _warnings:Array = [];
+
+		/**
+		 * Warning messages
+		 * */
+		[Bindable]
+		public function get warnings():Array {
+			return _warnings;
+		}
+
+		/**
+		 * @private
+		 */
+		public function set warnings(value:Array):void {
+			_warnings = value;
+		}
+		
+		
+		public var target:Object;
+		
+		
+		/**
+		 * Get an object that contains the properties that have been set on the component.
+		 * This does this by going through the history events and checking the changes.
+		 * 
+		 * WE SHOULD CHANGE THIS
+		 * */
+		public function getAppliedPropertiesFromHistory(document:IDocument, component:ComponentDescription, addToProperties:Boolean = true):Object {
+			var historyIndex:int = document.historyIndex;
+			var historyEvent:HistoryEventItem;
+			var historyItem:HistoryEvent;
+			var history:ArrayCollection;
+			var historyEvents:Array;
+			var eventsLength:int;
+			var propertiesObject:Object;
+			var stylesObject:Object;
+			var properties:Array;
+			var styles:Array;
+			
+			history = document.history;
+			propertiesObject = {};
+			stylesObject = {};
+			
+			if (history.length==0) return propertiesObject;
+			
+			// go back through the history of changes and 
+			// add the properties that have been set to an object
+			for (var i:int=historyIndex+1;i--;) {
+				historyItem = history.getItemAt(i) as HistoryEvent;
+				historyEvents = historyItem.historyEventItems;
+				eventsLength = historyEvents.length;
+				
+				for (var j:int=0;j<eventsLength;j++) {
+					historyEvent = historyEvents[j] as HistoryEventItem;
+					properties = historyEvent.properties;
+					styles = historyEvent.styles;
+		
+					if (historyEvent.targets.indexOf(component.instance)!=-1) {
+						for each (var property:String in properties) {
+							
+							if (property in propertiesObject) {
+								continue;
+							}
+							else {
+								propertiesObject[property] = historyEvent.propertyChanges.end[property];
+							}
+						}
+						
+						for each (var style:String in styles) {
+							
+							if (style in stylesObject) {
+								continue;
+							}
+							else {
+								stylesObject[style] = historyEvent.propertyChanges.end[style];
+							}
+						}
+					}
+					
+				}
+			}
+			
+			component.properties = propertiesObject;
+			component.styles = stylesObject;
+			
+			return propertiesObject;
+		}
+	}
+}
\ No newline at end of file