package widgets.supportClasses
{

import com.esri.ags.FeatureSet;
import com.esri.ags.Graphic;
import com.esri.ags.layers.FeatureLayer;
import com.esri.ags.layers.supportClasses.CodedValue;
import com.esri.ags.layers.supportClasses.CodedValueDomain;
import com.esri.ags.layers.supportClasses.FeatureType;
import com.esri.ags.layers.supportClasses.Field;
import com.esri.ags.layers.supportClasses.LayerDetails;

import mx.formatters.DateFormatter;

[Bindable]
public class ResultAttributes
{
    public var attributes:Object;
    public var title:String;
    public var content:String;
    public var link:String;
    public var linkAlias:String;

    public static function toResultAttributes(fields:XMLList,
                                              textDirection:String = null,
                                              graphic:Graphic = null,
                                              featureSet:FeatureSet = null,
                                              layer:FeatureLayer = null,
                                              layerDetails:LayerDetails = null,
                                              widgetTitle:String = null,
                                              titleField:String = null,
                                              linkField:String = null,
                                              linkAlias:String = null):ResultAttributes
    {
        var resultAttributes:ResultAttributes = new ResultAttributes;

        var value:String = "";
        var title:String = "";
        var content:String = "";
        var link:String = "";
        var linkAlias:String;

        var fieldsXMLList:XMLList = fields ? fields.field : null;
        if (fields && fields[0].@all[0] == "true")
        {
            if (layerDetails.fields)
            {
                for each (var field:Field in layerDetails.fields)
                {
                    if (field.name in graphic.attributes)
                    {
                        displayFields(field.name, getFieldXML(field.name, fieldsXMLList), field);
                    }
                }
            }
            else
            {
                for (var fieldName:String in graphic.attributes)
                {
                    displayFields(fieldName, getFieldXML(fieldName, fieldsXMLList), null);
                }
            }
        }
        else
        {
            for each (var fieldXML:XML in fieldsXMLList) // display the fields in the same order as specified
            {
                if (fieldXML.@name[0] in graphic.attributes)
                {
                    displayFields(fieldXML.@name[0], fieldXML, getField(layer, fieldXML.@name[0]));
                }
            }
        }
        resultAttributes.attributes = graphic.attributes;
        resultAttributes.title = title ? title : widgetTitle;
        resultAttributes.content = content;
        resultAttributes.link = link ? link : null;
        resultAttributes.linkAlias = linkAlias;

        function displayFields(fieldName:String, fieldXML:XML, field:Field):void
        {
            value = graphic.attributes[fieldName] ? String(graphic.attributes[fieldName]) : "";

            if (value)
            {
                var isDateField:Boolean;
                var useUTC:Boolean;
                var dateFormat:String;
                if (fieldXML)
                {
                    useUTC = fieldXML.format.@useutc[0] || fieldXML.@useutc[0] == "true";
                    dateFormat = fieldXML.format.@dateformat[0] || fieldXML.@dateformat[0];
                    if (dateFormat)
                    {
                        isDateField = true;
                    }
                }
                if (!isDateField && field)
                {
                    isDateField = field.type == Field.TYPE_DATE;
                }
                if (isDateField)
                {
                    var dateMS:Number = Number(value);
                    if (!isNaN(dateMS))
                    {
                        value = msToDate(dateMS, dateFormat, useUTC);
                    }
                }
                else
                {
                    var typeID:String = layerDetails.typeIdField ? graphic.attributes[layerDetails.typeIdField] : null;
                    if (fieldName == layerDetails.typeIdField)
                    {
                        var featureType:FeatureType = getFeatureType(layer, typeID);
                        if (featureType && featureType.name)
                        {
                            value = featureType.name;
                        }
                    }
                    else
                    {
                        var codedValue:CodedValue = getCodedValue(layer, fieldName, value, typeID);
                        if (codedValue)
                        {
                            value = codedValue.name;
                        }
                    }
                }
            }

            if (titleField && fieldName.toUpperCase() == titleField.toUpperCase())
            {
                title = value;
            }
            else if (linkField && fieldName.toUpperCase() == linkField.toUpperCase())
            {
                link = value;
                linkAlias = linkAlias;
            }
            else if (fieldName.toUpperCase() != "SHAPE_LENGTH" && fieldName.toUpperCase() != "SHAPE_AREA")
            {
                var fieldLabel:String;

                if (fieldXML && fieldXML.@alias[0])
                {
                    fieldLabel = fieldXML.@alias[0];
                }
                else
                {
                    fieldLabel = featureSet.fieldAliases[fieldName];
                }

                if (textDirection && textDirection == "rtl")
                {
                    content += value + " :" + fieldLabel + "\n";
                }
                else
                {
                    content += fieldLabel + ": " + value + "\n";
                }
            }
        }

        return resultAttributes;
    }

    private static function getFieldXML(fieldName:String, fields:XMLList):XML
    {
        var result:XML;

        for each (var fieldXML:XML in fields)
        {
            if (fieldName == fieldXML.@name[0])
            {
                result = fieldXML;
                break;
            }
        }

        return result;
    }

    private static function getField(layer:FeatureLayer, fieldName:String):Field
    {
        var result:Field;

        if (layer)
        {
            for each (var field:Field in layer.layerDetails.fields)
            {
                if (fieldName == field.name)
                {
                    result = field;
                    break;
                }
            }
        }

        return result;
    }

    private static function getFeatureType(layer:FeatureLayer, typeID:String):FeatureType
    {
        var result:FeatureType;

        if (layer)
        {
            for each (var featureType:FeatureType in layer.layerDetails.types)
            {
                if (typeID == featureType.id)
                {
                    result = featureType;
                    break;
                }
            }
        }

        return result;
    }

    private static function msToDate(ms:Number, dateFormat:String, useUTC:Boolean):String
    {
        var date:Date = new Date(ms);
        if (date.milliseconds == 999) // workaround for REST bug
        {
            date.milliseconds++;
        }
        if (useUTC)
        {
            date.minutes += date.timezoneOffset;
        }

        if (dateFormat)
        {
            var dateFormatter:DateFormatter = new DateFormatter();
            dateFormatter.formatString = dateFormat;
            var result:String = dateFormatter.format(date);
            if (result)
            {
                return result;
            }
            else
            {
                return dateFormatter.error;
            }
        }
        else
        {
            return date.toLocaleString();
        }
    }

    private static function getCodedValue(layer:FeatureLayer, fieldName:String, fieldValue:String, typeID:String):CodedValue
    {
        var result:CodedValue;

        var codedValueDomain:CodedValueDomain;
        if (typeID)
        {
            var featureType:FeatureType = getFeatureType(layer, typeID);
            if (featureType)
            {
                codedValueDomain = featureType.domains[fieldName] as CodedValueDomain;
            }
        }
        else
        {
            var field:Field = getField(layer, fieldName);
            if (field)
            {
                codedValueDomain = field.domain as CodedValueDomain;
            }
        }

        if (codedValueDomain)
        {
            for each (var codedValue:CodedValue in codedValueDomain.codedValues)
            {
                if (fieldValue == codedValue.code)
                {
                    result = codedValue;
                    break;
                }
            }
        }

        return result;
    }
}

}

package widgets.supportClasses
{

import com.esri.ags.FeatureSet;
import com.esri.ags.Graphic;
import com.esri.ags.layers.FeatureLayer;
import com.esri.ags.layers.supportClasses.CodedValue;
import com.esri.ags.layers.supportClasses.CodedValueDomain;
import com.esri.ags.layers.supportClasses.FeatureType;
import com.esri.ags.layers.supportClasses.Field;
import com.esri.ags.layers.supportClasses.LayerDetails;

import mx.formatters.DateFormatter;

[Bindable]
public class ResultAttributes
{
    public var attributes:Object;
    public var title:String;
    public var content:String;
    public var link:String;
    public var linkAlias:String;

    public static function toResultAttributes(fields:XMLList,
                                              textDirection:String = null,
                                              graphic:Graphic = null,
                                              featureSet:FeatureSet = null,
                                              layer:FeatureLayer = null,
                                              layerDetails:LayerDetails = null,
                                              widgetTitle:String = null,
                                              titleField:String = null,
                                              linkField:String = null,
                                              linkAlias:String = null):ResultAttributes
    {
        var resultAttributes:ResultAttributes = new ResultAttributes;

        var value:String = "";
        var title:String = "";
        var content:String = "";
        var link:String = "";
        var linkAlias:String;

        var fieldsXMLList:XMLList = fields ? fields.field : null;
        if (fields && fields[0].@all[0] == "true")
        {
            if (layerDetails.fields)
            {
                for each (var field:Field in layerDetails.fields)
                {
                    if (field.name in graphic.attributes)
                    {
                        displayFields(field.name, getFieldXML(field.name, fieldsXMLList), field);
                    }
                }
            }
            else
            {
                for (var fieldName:String in graphic.attributes)
                {
                    displayFields(fieldName, getFieldXML(fieldName, fieldsXMLList), null);
                }
            }
        }
        else
        {
            for each (var fieldXML:XML in fieldsXMLList) // display the fields in the same order as specified
            {
                if (fieldXML.@name[0] in graphic.attributes)
                {
                    displayFields(fieldXML.@name[0], fieldXML, getField(layer, fieldXML.@name[0]));
                }
            }
        }
        resultAttributes.attributes = graphic.attributes;
        resultAttributes.title = title ? title : widgetTitle;
        resultAttributes.content = content;
        resultAttributes.link = link ? link : null;
        resultAttributes.linkAlias = linkAlias;

        function displayFields(fieldName:String, fieldXML:XML, field:Field):void
        {
            var fieldNameTextValue:String = graphic.attributes[fieldName];
            value = fieldNameTextValue ? fieldNameTextValue : "";

            if (value)
            {
                var isDateField:Boolean;
                var useUTC:Boolean;
                var dateFormat:String;
                if (fieldXML)
                {
                    useUTC = fieldXML.format.@useutc[0] || fieldXML.@useutc[0] == "true";
                    dateFormat = fieldXML.format.@dateformat[0] || fieldXML.@dateformat[0];
                    if (dateFormat)
                    {
                        isDateField = true;
                    }
                }
                if (!isDateField && field)
                {
                    isDateField = field.type == Field.TYPE_DATE;
                }
                if (isDateField)
                {
                    var dateMS:Number = Number(value);
                    if (!isNaN(dateMS))
                    {
                        value = msToDate(dateMS, dateFormat, useUTC);
                    }
                }
                else
                {
                    var typeID:String = layerDetails.typeIdField ? graphic.attributes[layerDetails.typeIdField] : null;
                    if (fieldName == layerDetails.typeIdField)
                    {
                        var featureType:FeatureType = getFeatureType(layer, typeID);
                        if (featureType && featureType.name)
                        {
                            value = featureType.name;
                        }
                    }
                    else
                    {
                        var codedValue:CodedValue = getCodedValue(layer, fieldName, value, typeID);
                        if (codedValue)
                        {
                            value = codedValue.name;
                        }
                    }
                }
            }

            if (titleField && fieldName.toUpperCase() == titleField.toUpperCase())
            {
                title = value;
            }
            else if (linkField && fieldName.toUpperCase() == linkField.toUpperCase())
            {
                link = value;
                linkAlias = linkAlias;
            }
            else if (fieldName.toUpperCase() != "SHAPE_LENGTH" && fieldName.toUpperCase() != "SHAPE_AREA")
            {
                var fieldLabel:String;

                if (fieldXML && fieldXML.@alias[0])
                {
                    fieldLabel = fieldXML.@alias[0];
                }
                else
                {
                    fieldLabel = featureSet.fieldAliases[fieldName];
                }

                if (textDirection && textDirection == "rtl")
                {
                    content += value + " :" + fieldLabel + "\n";
                }
                else
                {
                    content += fieldLabel + ": " + value + "\n";
                }
            }
        }

        return resultAttributes;
    }

    private static function getFieldXML(fieldName:String, fields:XMLList):XML
    {
        var result:XML;

        for each (var fieldXML:XML in fields)
        {
            if (fieldName == fieldXML.@name[0])
            {
                result = fieldXML;
                break;
            }
        }

        return result;
    }

    private static function getField(layer:FeatureLayer, fieldName:String):Field
    {
        var result:Field;

        if (layer)
        {
            for each (var field:Field in layer.layerDetails.fields)
            {
                if (fieldName == field.name)
                {
                    result = field;
                    break;
                }
            }
        }

        return result;
    }

    private static function getFeatureType(layer:FeatureLayer, typeID:String):FeatureType
    {
        var result:FeatureType;

        if (layer)
        {
            for each (var featureType:FeatureType in layer.layerDetails.types)
            {
                if (typeID == featureType.id)
                {
                    result = featureType;
                    break;
                }
            }
        }

        return result;
    }

    private static function msToDate(ms:Number, dateFormat:String, useUTC:Boolean):String
    {
        var date:Date = new Date(ms);
        if (date.milliseconds == 999) // workaround for REST bug
        {
            date.milliseconds++;
        }
        if (useUTC)
        {
            date.minutes += date.timezoneOffset;
        }

        if (dateFormat)
        {
            var dateFormatter:DateFormatter = new DateFormatter();
            dateFormatter.formatString = dateFormat;
            var result:String = dateFormatter.format(date);
            if (result)
            {
                return result;
            }
            else
            {
                return dateFormatter.error;
            }
        }
        else
        {
            return date.toLocaleString();
        }
    }

    private static function getCodedValue(layer:FeatureLayer, fieldName:String, fieldValue:String, typeID:String):CodedValue
    {
        var result:CodedValue;

        var codedValueDomain:CodedValueDomain;
        if (typeID)
        {
            var featureType:FeatureType = getFeatureType(layer, typeID);
            if (featureType)
            {
                codedValueDomain = featureType.domains[fieldName] as CodedValueDomain;
            }
        }
        else
        {
            var field:Field = getField(layer, fieldName);
            if (field)
            {
                codedValueDomain = field.domain as CodedValueDomain;
            }
        }

        if (codedValueDomain)
        {
            for each (var codedValue:CodedValue in codedValueDomain.codedValues)
            {
                if (fieldValue == codedValue.code)
                {
                    result = codedValue;
                    break;
                }
            }
        }

        return result;
    }
}

}

Improve ResultAttribute#toResultAttributes field value handling.


// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2011  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
package com.kaltura.delegates {

	import com.kaltura.config.IKalturaConfig;
	import com.kaltura.config.KalturaConfig;
	import com.kaltura.core.KClassFactory;
	import com.kaltura.encryption.MD5;
	import com.kaltura.errors.KalturaError;
	import com.kaltura.events.KalturaEvent;
	import com.kaltura.net.KalturaCall;

	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.HTTPStatusEvent;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.TimerEvent;
	import flash.net.FileReference;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.net.URLRequestMethod;
	import flash.utils.Timer;
	import flash.utils.getDefinitionByName;

	public class WebDelegateBase extends EventDispatcher implements IKalturaCallDelegate {

		public static var CONNECT_TIME:int = 60000; //60 secs
		public static var LOAD_TIME:int = 120000; //120 secs

		protected var connectTimer:Timer;
		protected var loadTimer:Timer;

		protected var _call:KalturaCall;
		protected var _config:KalturaConfig;

		protected var loader:URLLoader;
		protected var fileRef:FileReference;

		//Setters & getters
		public function get call():KalturaCall {
			return _call;
		}

		public function set call(newVal:KalturaCall):void {
			_call = newVal;
		}

		public function get config():IKalturaConfig {
			return _config;
		}

		public function set config(newVal:IKalturaConfig):void {
			_config = newVal as KalturaConfig;
		}

		public function WebDelegateBase(call:KalturaCall = null, config:KalturaConfig = null) {
			this.call = call;
			this.config = config;
			if (!call)
				return; //maybe a multi request
			if (call.useTimeout) {
				connectTimer = new Timer(CONNECT_TIME, 1);
				connectTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onConnectTimeout);

				loadTimer = new Timer(LOAD_TIME, 1);
				loadTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onLoadTimeOut);
			}
			execute();
		}

		public function close():void {
			try {
				loader.close();
			}
			catch (e:*) {
			}

			if (call.useTimeout) {
				connectTimer.stop();
				loadTimer.stop();
			}
		}

		protected function onConnectTimeout(event:TimerEvent):void {
			var kError:KalturaError = new KalturaError();
			kError.errorCode = "CONNECTION_TIMEOUT";
			kError.errorMsg = "Connection Timeout: " + CONNECT_TIME / 1000 + " sec with no post command from kaltura client.";
			_call.handleError(kError);
			dispatchEvent(new KalturaEvent(KalturaEvent.FAILED, false, false, false, null, kError));

			loadTimer.stop();
			close();
		}

		protected function onLoadTimeOut(event:TimerEvent):void {
			connectTimer.stop();

			close();

			var kError:KalturaError = new KalturaError();
			kError.errorCode = "POST_TIMEOUT";
			kError.errorMsg = "Post Timeout: " + LOAD_TIME / 1000 + " sec with no post result.";
			_call.handleError(kError);
			dispatchEvent(new KalturaEvent(KalturaEvent.FAILED, false, false, false, null, kError));
		}

		protected function execute():void {
			if (call == null) {
				throw new Error('No call defined.');
			}
			post(); //post the call
		}

		/**
		* Helper function for sending the call straight to the server
		*/
		protected function post():void {

			addOptionalArguments();

			formatRequest();

			sendRequest();

			if (call.useTimeout) {
				connectTimer.start();
			}
		}

		protected function formatRequest():void {
			//The configuration is stronger then the args
			if (_config.partnerId != null && _call.args["partnerId"] == -1)
				_call.setRequestArgument("partnerId", _config.partnerId);

			if (_config.ks != null)
				_call.setRequestArgument("ks", _config.ks);

			if (_config.clientTag != null)
				_call.setRequestArgument("clientTag", _config.clientTag);

			_call.setRequestArgument("ignoreNull", _config.ignoreNull);

			//Create signature hash.
			//call.setRequestArgument("kalsig", getMD5Checksum(call));
		}

		protected function getMD5Checksum(call:KalturaCall):String {
			var props:Array = new Array();
			for each (var prop:String in call.args)
				props.push(prop);

			props.push("service");
			props.push("action");
			props.sort();

			var s:String;
			for each (prop in props) {
				s += prop;

				if (prop == "service")
					s += call.service;
				else if (prop == "action")
					s += call.action;
				else
					s += call.args[prop];
			}

			return MD5.encrypt(s);
		}

		protected function sendRequest():void {

			//construct the loader
			createURLLoader();

			//Create signature hash.
			var kalsig:String = getMD5Checksum(call);

			//create the service request for normal calls
			var url:String = _config.protocol + _config.domain + "/" + _config.srvUrl + "?service=" + call.service + "&action=" + call.action + "&kalsig=" + kalsig;;

			if (_call.method == URLRequestMethod.GET)
				url += "&";

			var req:URLRequest = new URLRequest(url);
			req.contentType = "application/x-www-form-urlencoded";
			req.method = call.method;
			req.data = call.args;

			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.load(req);
		}

		protected function createURLLoader():void {
			loader = new URLLoader();
			loader.addEventListener(Event.COMPLETE, onDataComplete);
			loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, onHTTPStatus);
			loader.addEventListener(IOErrorEvent.IO_ERROR, onError);
			loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
			loader.addEventListener(Event.OPEN, onOpen);
		}

		protected function onHTTPStatus(event:HTTPStatusEvent):void {
		}

		protected function onOpen(event:Event):void {
			if (call.useTimeout) {
				connectTimer.stop();
				loadTimer.start();
			}
		}

		protected function addOptionalArguments():void {
			//add optional args here
		}

		// Event Handlers

		/**
		 * try to process received data.
		 * if procesing failed, let call handle the processing error
		 * @param event load complete event
		 */
		protected function onDataComplete(event:Event):void {
			try {
				handleResult(XML(event.target.data));
			}
			catch (e:Error) {
				var kErr:KalturaError = new KalturaError();
				kErr.errorCode = String(e.errorID);
				kErr.errorMsg = e.message;
				_call.handleError(kErr);
			}
		}

		/**
		 * handle io or security error events from the loader.
		 * create relevant KalturaError, let the call process it.
		 * @param event
		 */
		protected function onError(event:ErrorEvent):void {
			clean();
			var kError:KalturaError = createKalturaError(event, loader.data);

			if (!kError) {
				kError = new KalturaError();
				kError.errorMsg = event.text;
				//kError.errorCode;
			}

			call.handleError(kError);

			dispatchEvent(new KalturaEvent(KalturaEvent.FAILED, false, false, false, null, kError));
		}

		/**
		 * parse the server's response and let the call process it.
		 * @param result  server's response
		 */
		protected function handleResult(result:XML):void {
			clean();

			var error:KalturaError = validateKalturaResponse(result);

			if (error == null) {
				var digestedResult:Object = parse(result);
				call.handleResult(digestedResult);
			}
			else {
				call.handleError(error);
			}
		}

		/**
		* stop timers and clean event listeners
		 */
		protected function clean():void {
			if (call.useTimeout) {
				connectTimer.stop();
				loadTimer.stop();
			}

			if (loader == null) {
				return;
			}

			loader.removeEventListener(Event.COMPLETE, onDataComplete);
			loader.removeEventListener(IOErrorEvent.IO_ERROR, onError);
			loader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
			loader.removeEventListener(Event.OPEN, onOpen);
		}

		/**
		* create the correct object and populate it with the given values. if the needed class is not found
		 * in the file, a generic object is created with attributes matching the XML attributes.
		* Override this parssing function in the specific delegate to create the correct object.
		* @param   result      instance attributes
		* @return an instance of the class declared by the given XML.
		* */
		public function parse(result:XML):* {
			//by defualt create the response object
			var cls:Class;
			try {
				cls = getDefinitionByName('com.kaltura.vo.' + result.result.objectType) as Class;
			}
			catch (e:Error) {
				cls = Object;
			}
			var obj:* = (new KClassFactory(cls)).newInstanceFromXML(result.result);
			return obj;
		}

		/**
		 * If the result string holds an error, return a KalturaError object with
		 * relevant values. <br/>
		 * Overide this to create validation object and fill it.
		 * @param result  the string returned from the server.
		 * @return  matching error object
		 */
		protected function validateKalturaResponse(result:String):KalturaError {
			var kError:KalturaError = null;
			var xml:XML = XML(result);
			if (xml.result.hasOwnProperty('error')
				&& xml.result.error.hasOwnProperty('code')
				&& xml.result.error.hasOwnProperty('message')) {

				kError = new KalturaError();
				kError.errorCode = String(xml.result.error.code);
				kError.errorMsg = xml.result.error.message;
				dispatchEvent(new KalturaEvent(KalturaEvent.FAILED, false, false, false, null, kError));
			}

			return kError;
		}

		/**
		 * create error object and fill it with relevant details
		 * @param event
		 * @param loaderData
		 * @return detailed KalturaError to be processed
		 */
		protected function createKalturaError(event:ErrorEvent, loaderData:*):KalturaError {
			var ke:KalturaError = new KalturaError();
			ke.errorMsg = event.text;
			return ke;
		}

		/**
		* create the url that is used for serve actions
		* @param call    the KalturaCall that defines the required parameters
		 * @return URLRequest with relevant parameters
		* */
		public function getServeUrl(call:KalturaCall):URLRequest {
			var url:String = _config.protocol + _config.domain + "/" + _config.srvUrl + "?service=" + call.service + "&action=" + call.action;
			for (var key:String in call.args) {
				url += "&" + key + "=" + call.args[key];
			}
			var req:URLRequest = new URLRequest(url);
			req.contentType = "application/x-www-form-urlencoded";
			req.method = call.method;
//          req.data = call.args;
			return req;
		}

	}
}

// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2011  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
package com.kaltura.delegates {

	import com.kaltura.config.IKalturaConfig;
	import com.kaltura.config.KalturaConfig;
	import com.kaltura.core.KClassFactory;
	import com.kaltura.encryption.MD5;
	import com.kaltura.errors.KalturaError;
	import com.kaltura.events.KalturaEvent;
	import com.kaltura.net.KalturaCall;

	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.HTTPStatusEvent;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.TimerEvent;
	import flash.net.FileReference;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.net.URLRequestMethod;
	import flash.utils.Timer;
	import flash.utils.getDefinitionByName;

	public class WebDelegateBase extends EventDispatcher implements IKalturaCallDelegate {

		public static var CONNECT_TIME:int = 120000; //120 secs
		public static var LOAD_TIME:int = 120000; //120 secs

		protected var connectTimer:Timer;
		protected var loadTimer:Timer;

		protected var _call:KalturaCall;
		protected var _config:KalturaConfig;

		protected var loader:URLLoader;
		protected var fileRef:FileReference;

		//Setters & getters
		public function get call():KalturaCall {
			return _call;
		}

		public function set call(newVal:KalturaCall):void {
			_call = newVal;
		}

		public function get config():IKalturaConfig {
			return _config;
		}

		public function set config(newVal:IKalturaConfig):void {
			_config = newVal as KalturaConfig;
		}

		public function WebDelegateBase(call:KalturaCall = null, config:KalturaConfig = null) {
			this.call = call;
			this.config = config;
			if (!call)
				return; //maybe a multi request
			if (call.useTimeout) {
				connectTimer = new Timer(CONNECT_TIME, 1);
				connectTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onConnectTimeout);

				loadTimer = new Timer(LOAD_TIME, 1);
				loadTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onLoadTimeOut);
			}
			execute();
		}

		public function close():void {
			try {
				loader.close();
			}
			catch (e:*) {
			}

			if (call.useTimeout) {
				connectTimer.stop();
				loadTimer.stop();
			}
		}

		protected function onConnectTimeout(event:TimerEvent):void {
			var kError:KalturaError = new KalturaError();
			kError.errorCode = "CONNECTION_TIMEOUT";
			kError.errorMsg = "Connection Timeout: " + CONNECT_TIME / 1000 + " sec with no post command from kaltura client.";
			_call.handleError(kError);
			dispatchEvent(new KalturaEvent(KalturaEvent.FAILED, false, false, false, null, kError));

			loadTimer.stop();
			close();
		}

		protected function onLoadTimeOut(event:TimerEvent):void {
			connectTimer.stop();

			close();

			var kError:KalturaError = new KalturaError();
			kError.errorCode = "POST_TIMEOUT";
			kError.errorMsg = "Post Timeout: " + LOAD_TIME / 1000 + " sec with no post result.";
			_call.handleError(kError);
			dispatchEvent(new KalturaEvent(KalturaEvent.FAILED, false, false, false, null, kError));
		}

		protected function execute():void {
			if (call == null) {
				throw new Error('No call defined.');
			}
			post(); //post the call
		}

		/**
		* Helper function for sending the call straight to the server
		*/
		protected function post():void {

			addOptionalArguments();

			formatRequest();

			sendRequest();

			if (call.useTimeout) {
				connectTimer.start();
			}
		}

		protected function formatRequest():void {
			//The configuration is stronger then the args
			if (_config.partnerId != null && _call.args["partnerId"] == -1)
				_call.setRequestArgument("partnerId", _config.partnerId);

			if (_config.ks != null)
				_call.setRequestArgument("ks", _config.ks);

			if (_config.clientTag != null)
				_call.setRequestArgument("clientTag", _config.clientTag);

			_call.setRequestArgument("ignoreNull", _config.ignoreNull);

			//Create signature hash.
			//call.setRequestArgument("kalsig", getMD5Checksum(call));
		}

		protected function getMD5Checksum(call:KalturaCall):String {
			var props:Array = new Array();
			for each (var prop:String in call.args)
				props.push(prop);

			props.push("service");
			props.push("action");
			props.sort();

			var s:String;
			for each (prop in props) {
				s += prop;

				if (prop == "service")
					s += call.service;
				else if (prop == "action")
					s += call.action;
				else
					s += call.args[prop];
			}

			return MD5.encrypt(s);
		}

		protected function sendRequest():void {

			//construct the loader
			createURLLoader();

			//Create signature hash.
			var kalsig:String = getMD5Checksum(call);

			//create the service request for normal calls
			var url:String = _config.protocol + _config.domain + "/" + _config.srvUrl + "?service=" + call.service + "&action=" + call.action + "&kalsig=" + kalsig;;

			if (_call.method == URLRequestMethod.GET)
				url += "&";

			var req:URLRequest = new URLRequest(url);
			req.contentType = "application/x-www-form-urlencoded";
			req.method = call.method;
			req.data = call.args;

			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.load(req);
		}

		protected function createURLLoader():void {
			loader = new URLLoader();
			loader.addEventListener(Event.COMPLETE, onDataComplete);
			loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, onHTTPStatus);
			loader.addEventListener(IOErrorEvent.IO_ERROR, onError);
			loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
			loader.addEventListener(Event.OPEN, onOpen);
		}

		protected function onHTTPStatus(event:HTTPStatusEvent):void {
		}

		protected function onOpen(event:Event):void {
			if (call.useTimeout) {
				connectTimer.stop();
				loadTimer.start();
			}
		}

		protected function addOptionalArguments():void {
			//add optional args here
		}

		// Event Handlers

		/**
		 * try to process received data.
		 * if procesing failed, let call handle the processing error
		 * @param event load complete event
		 */
		protected function onDataComplete(event:Event):void {
			try {
				handleResult(XML(event.target.data));
			}
			catch (e:Error) {
				var kErr:KalturaError = new KalturaError();
				kErr.errorCode = String(e.errorID);
				kErr.errorMsg = e.message;
				_call.handleError(kErr);
			}
		}

		/**
		 * handle io or security error events from the loader.
		 * create relevant KalturaError, let the call process it.
		 * @param event
		 */
		protected function onError(event:ErrorEvent):void {
			clean();
			var kError:KalturaError = createKalturaError(event, loader.data);

			if (!kError) {
				kError = new KalturaError();
				kError.errorMsg = event.text;
				//kError.errorCode;
			}

			call.handleError(kError);

			dispatchEvent(new KalturaEvent(KalturaEvent.FAILED, false, false, false, null, kError));
		}

		/**
		 * parse the server's response and let the call process it.
		 * @param result  server's response
		 */
		protected function handleResult(result:XML):void {
			clean();

			var error:KalturaError = validateKalturaResponse(result);

			if (error == null) {
				var digestedResult:Object = parse(result);
				call.handleResult(digestedResult);
			}
			else {
				call.handleError(error);
			}
		}

		/**
		* stop timers and clean event listeners
		 */
		protected function clean():void {
			if (call.useTimeout) {
				connectTimer.stop();
				loadTimer.stop();
			}

			if (loader == null) {
				return;
			}

			loader.removeEventListener(Event.COMPLETE, onDataComplete);
			loader.removeEventListener(IOErrorEvent.IO_ERROR, onError);
			loader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
			loader.removeEventListener(Event.OPEN, onOpen);
		}

		/**
		* create the correct object and populate it with the given values. if the needed class is not found
		 * in the file, a generic object is created with attributes matching the XML attributes.
		* Override this parssing function in the specific delegate to create the correct object.
		* @param   result      instance attributes
		* @return an instance of the class declared by the given XML.
		* */
		public function parse(result:XML):* {
			//by defualt create the response object
			var cls:Class;
			try {
				cls = getDefinitionByName('com.kaltura.vo.' + result.result.objectType) as Class;
			}
			catch (e:Error) {
				cls = Object;
			}
			var obj:* = (new KClassFactory(cls)).newInstanceFromXML(result.result);
			return obj;
		}

		/**
		 * If the result string holds an error, return a KalturaError object with
		 * relevant values. <br/>
		 * Overide this to create validation object and fill it.
		 * @param result  the string returned from the server.
		 * @return  matching error object
		 */
		protected function validateKalturaResponse(result:String):KalturaError {
			var kError:KalturaError = null;
			var xml:XML = XML(result);
			if (xml.result.hasOwnProperty('error')
				&& xml.result.error.hasOwnProperty('code')
				&& xml.result.error.hasOwnProperty('message')) {

				kError = new KalturaError();
				kError.errorCode = String(xml.result.error.code);
				kError.errorMsg = xml.result.error.message;
				dispatchEvent(new KalturaEvent(KalturaEvent.FAILED, false, false, false, null, kError));
			}

			return kError;
		}

		/**
		 * create error object and fill it with relevant details
		 * @param event
		 * @param loaderData
		 * @return detailed KalturaError to be processed
		 */
		protected function createKalturaError(event:ErrorEvent, loaderData:*):KalturaError {
			var ke:KalturaError = new KalturaError();
			ke.errorMsg = event.text;
			return ke;
		}

		/**
		* create the url that is used for serve actions
		* @param call    the KalturaCall that defines the required parameters
		 * @return URLRequest with relevant parameters
		* */
		public function getServeUrl(call:KalturaCall):URLRequest {
			var url:String = _config.protocol + _config.domain + "/" + _config.srvUrl + "?service=" + call.service + "&action=" + call.action;
			for (var key:String in call.args) {
				url += "&" + key + "=" + call.args[key];
			}
			var req:URLRequest = new URLRequest(url);
			req.contentType = "application/x-www-form-urlencoded";
			req.method = call.method;
//          req.data = call.args;
			return req;
		}

	}
}

increase connect timeout to 120 secs

fwr: increase connect timeout to 120 secs

git-svn-id: 8a2ccb88241e16c78017770bc38d91d6d5396a5a@94136 6b8eccd3-e8c5-4e7d-8186-e12b5326b719


//
// Nenya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/nenya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

package com.threerings.cast {

import flash.geom.Point;

import com.threerings.util.Hashable;
import com.threerings.util.Log;
import com.threerings.util.Map;
import com.threerings.util.StringUtil;
import com.threerings.util.Maps;
import com.threerings.util.maps.LRMap;

/**
 * The character manager provides facilities for constructing sprites that
 * are used to represent characters in a scene. It also handles the
 * compositing and caching of composited character animations.
 */
public class CharacterManager
{
    private static var log :Log = Log.getLog(CharacterManager);

    /**
     * Constructs the character manager.
     */
    public function CharacterManager (crepo :ComponentRepository)
    {
        // keep this around
        _crepo = crepo;

        for each (var action :ActionSequence in crepo.getActionSequences()) {
            _actions.put(action.name, action);
        }
    }

    /**
     * Returns a {@link CharacterSprite} representing the character
     * described by the given {@link CharacterDescriptor}, or
     * null if an error occurs.
     *
     * @param desc the character descriptor.
     */
    public function getCharacter (desc :CharacterDescriptor,
        charClass :Class = null) :CharacterSprite
    {
        if (charClass == null) {
            charClass = _charClass;
        }

        try {
            var sprite :CharacterSprite = new charClass();
            sprite.init(desc, this);
            return sprite;

        } catch (e :Error) {
            log.warning("Failed to instantiate character sprite.", e);
            return null;
        }
        return getCharacter(desc, charClass);
    }

    public function getActionSequence (action :String) :ActionSequence
    {
        return _actions.get(action);
    }

    public function getActionFrames (descrip :CharacterDescriptor, action :String) :ActionFrames
    {
        if (!isLoaded(descrip)) {
            return null;
        }

        var key :FrameKey = new FrameKey(descrip, action);

        var frames :ActionFrames = _actionFrames.get(key);
        if (frames == null) {
            // this doesn't actually composite the images, but prepares an
            // object to be able to do so
            frames = createCompositeFrames(descrip, action);
            _actionFrames.put(key, frames);
        }

        return frames;
    }

    /**
     * Returns whether all the components are loaded and ready to go.
     */
    protected function isLoaded (descrip :CharacterDescriptor) :Boolean
    {
        var cids :Array = descrip.getComponentIds();
        var ccount :int = cids.length;

        for (var ii :int = 0; ii < ccount; ii++) {
            var ccomp :CharacterComponent = _crepo.getComponent(cids[ii]);
            if (!ccomp.isLoaded()) {
                return false;
            }
        }

        return true;
    }

    public function load (descrip :CharacterDescriptor, notify :Function) :void
    {
        _crepo.load(descrip.getComponentIds(), notify);
    }

    protected function createCompositeFrames (descrip :CharacterDescriptor,
        action :String) :ActionFrames
    {
        var cids :Array = descrip.getComponentIds();
        var ccount :int = cids.length;

        var zations :Array = descrip.getColorizations();
        var xlations :Array = descrip.getTranslations();

        log.debug("Compositing action [action=" + action +
                  ", descrip=" + descrip + "].");

        // this will be used to construct any shadow layers
        var shadows :Map = null; /* of String, Array<TranslatedComponent> */

        // maps components by class name for masks
        var ccomps :Map = Maps.newMapOf(String); /* of String, ArrayList<TranslatedComponent> */

        // create colorized versions of all of the source action frames
        var sources :Array = [];
        for (var ii :int = 0; ii < ccount; ii++) {
            var cframes :ComponentFrames = new ComponentFrames();
            sources.push(cframes);
            var ccomp :CharacterComponent = cframes.ccomp = _crepo.getComponent(cids[ii]);

            // load up the main component images
            var source :ActionFrames = ccomp.getFrames(action, null);
            if (source == null) {
                var errmsg :String = "Cannot composite action frames; no such " +
                    "action for component [action=" + action +
                    ", desc=" + descrip + ", comp=" + ccomp + "]";
                throw new Error(errmsg);
            }
            source = (zations == null || zations[ii] == null) ?
                source : source.cloneColorized(zations[ii]);
            var xlation :Point = (xlations == null) ? null : xlations[ii];
            cframes.frames = (xlation == null) ?
                source : source.cloneTranslated(xlation.x, xlation.y);

            // store the component with its translation under its class for masking
            var tcomp :TranslatedComponent = new TranslatedComponent(ccomp, xlation);
            var tcomps :Array = ccomps.get(ccomp.componentClass.name);
            if (tcomps == null) {
                ccomps.put(ccomp.componentClass.name, tcomps = []);
            }
            tcomps.push(tcomp);

            // if this component has a shadow, make a note of it
            if (ccomp.componentClass.isShadowed()) {
                if (shadows == null) {
                    shadows = Maps.newMapOf(String);
                }
                var shadlist :Array = shadows.get(ccomp.componentClass.shadow);
                if (shadlist == null) {
                    shadows.put(ccomp.componentClass.shadow, shadlist = []);
                }
                shadlist.push(tcomp);
            }
        }

/* TODO - Implement shadows & masks - I don't actually know if/where we use these, though.
        // now create any necessary shadow layers
        if (shadows != null) {
            for (Map.Entry<String, ArrayList<TranslatedComponent>> entry : shadows.entrySet()) {
                ComponentFrames scf = compositeShadow(action, entry.getKey(), entry.getValue());
                if (scf != null) {
                    sources.add(scf);
                }
            }
        }

        // add any necessary masks
        for (ComponentFrames cframes : sources) {
            ArrayList<TranslatedComponent> mcomps = ccomps.get(cframes.ccomp.componentClass.mask);
            if (mcomps != null) {
                cframes.frames = compositeMask(action, cframes.ccomp, cframes.frames, mcomps);
            }
        }
*/
        // use those to create an entity that will lazily composite things
        // together as they are needed
        return new CompositedActionFrames(_frameCache, _actions.get(action), sources);
    }

    protected var _crepo :ComponentRepository;

    protected var _actions :Map = Maps.newMapOf(String);

    protected var _actionFrames :Map = Maps.newMapOf(FrameKey);

    protected var _frameCache :LRMap = new LRMap(Maps.newMapOf(CompositedFramesKey), MAX_FRAMES);

    protected var _charClass :Class;

    protected static const MAX_FRAMES :int = 1000;
}
}

import com.threerings.util.Hashable;
import com.threerings.util.StringUtil;
import com.threerings.cast.CharacterDescriptor;

class FrameKey
    implements Hashable
{
    public var desc :CharacterDescriptor;

    public var action :String;

    public function FrameKey (desc :CharacterDescriptor, action :String)
    {
        this.desc = desc;
        this.action = action;
    }

    public function hashCode () :int
    {
        return desc.hashCode() ^ StringUtil.hashCode(action);
    }

    public function equals (other :Object) :Boolean
    {
        if (other is FrameKey) {
            var okey :FrameKey = FrameKey(other);
            return okey.desc.equals(desc) && okey.action == action;
        } else {
            return false;
        }
    }
}

import flash.geom.Point;

import com.threerings.cast.ActionFrames;
import com.threerings.cast.CharacterComponent;

class TranslatedComponent
{
    public var ccomp :CharacterComponent;
    public var xlation :Point;

    public function TranslatedComponent (ccomp :CharacterComponent, xlation :Point)
    {
        this.ccomp = ccomp;
        this.xlation = xlation;
    }

    public function getFrames (action :String, type :String) :ActionFrames
    {
        var frames :ActionFrames = ccomp.getFrames(action, type);
        return (frames == null || xlation == null) ?
            frames : frames.cloneTranslated(xlation.x, xlation.y);
    }

}

//
// Nenya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/nenya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

package com.threerings.cast {

import flash.geom.Point;

import com.threerings.util.Hashable;
import com.threerings.util.Log;
import com.threerings.util.Map;
import com.threerings.util.StringUtil;
import com.threerings.util.Maps;
import com.threerings.util.maps.LRMap;

/**
 * The character manager provides facilities for constructing sprites that
 * are used to represent characters in a scene. It also handles the
 * compositing and caching of composited character animations.
 */
public class CharacterManager
{
    private static var log :Log = Log.getLog(CharacterManager);

    /**
     * Constructs the character manager.
     */
    public function CharacterManager (crepo :ComponentRepository)
    {
        // keep this around
        _crepo = crepo;

        for each (var action :ActionSequence in crepo.getActionSequences()) {
            _actions.put(action.name, action);
        }
    }

    /**
     * Returns a {@link CharacterSprite} representing the character
     * described by the given {@link CharacterDescriptor}, or
     * null if an error occurs.
     *
     * @param desc the character descriptor.
     */
    public function getCharacter (desc :CharacterDescriptor,
        charClass :Class = null) :CharacterSprite
    {
        if (charClass == null) {
            charClass = _charClass;
        }

        try {
            var sprite :CharacterSprite = new charClass();
            sprite.init(desc, this);
            return sprite;

        } catch (e :Error) {
            log.warning("Failed to instantiate character sprite.", e);
            return null;
        }
        return getCharacter(desc, charClass);
    }

    public function getActionSequence (action :String) :ActionSequence
    {
        return _actions.get(action);
    }

    public function getComponent (compId :int) :CharacterComponent
    {
        return _crepo.getComponent(compId);
    }

    public function getActionFrames (descrip :CharacterDescriptor, action :String) :ActionFrames
    {
        if (!isLoaded(descrip)) {
            return null;
        }

        var key :FrameKey = new FrameKey(descrip, action);

        var frames :ActionFrames = _actionFrames.get(key);
        if (frames == null) {
            // this doesn't actually composite the images, but prepares an
            // object to be able to do so
            frames = createCompositeFrames(descrip, action);
            _actionFrames.put(key, frames);
        }

        return frames;
    }

    /**
     * Returns whether all the components are loaded and ready to go.
     */
    protected function isLoaded (descrip :CharacterDescriptor) :Boolean
    {
        var cids :Array = descrip.getComponentIds();
        var ccount :int = cids.length;

        for (var ii :int = 0; ii < ccount; ii++) {
            var ccomp :CharacterComponent = _crepo.getComponent(cids[ii]);
            if (!ccomp.isLoaded()) {
                return false;
            }
        }

        return true;
    }

    public function load (descrip :CharacterDescriptor, notify :Function) :void
    {
        _crepo.load(descrip.getComponentIds(), notify);
    }

    protected function createCompositeFrames (descrip :CharacterDescriptor,
        action :String) :ActionFrames
    {
        var cids :Array = descrip.getComponentIds();
        var ccount :int = cids.length;

        var zations :Array = descrip.getColorizations();
        var xlations :Array = descrip.getTranslations();

        log.debug("Compositing action [action=" + action +
                  ", descrip=" + descrip + "].");

        // this will be used to construct any shadow layers
        var shadows :Map = null; /* of String, Array<TranslatedComponent> */

        // maps components by class name for masks
        var ccomps :Map = Maps.newMapOf(String); /* of String, ArrayList<TranslatedComponent> */

        // create colorized versions of all of the source action frames
        var sources :Array = [];
        for (var ii :int = 0; ii < ccount; ii++) {
            var cframes :ComponentFrames = new ComponentFrames();
            sources.push(cframes);
            var ccomp :CharacterComponent = cframes.ccomp = _crepo.getComponent(cids[ii]);

            // load up the main component images
            var source :ActionFrames = ccomp.getFrames(action, null);
            if (source == null) {
                var errmsg :String = "Cannot composite action frames; no such " +
                    "action for component [action=" + action +
                    ", desc=" + descrip + ", comp=" + ccomp + "]";
                throw new Error(errmsg);
            }
            source = (zations == null || zations[ii] == null) ?
                source : source.cloneColorized(zations[ii]);
            var xlation :Point = (xlations == null) ? null : xlations[ii];
            cframes.frames = (xlation == null) ?
                source : source.cloneTranslated(xlation.x, xlation.y);

            // store the component with its translation under its class for masking
            var tcomp :TranslatedComponent = new TranslatedComponent(ccomp, xlation);
            var tcomps :Array = ccomps.get(ccomp.componentClass.name);
            if (tcomps == null) {
                ccomps.put(ccomp.componentClass.name, tcomps = []);
            }
            tcomps.push(tcomp);

            // if this component has a shadow, make a note of it
            if (ccomp.componentClass.isShadowed()) {
                if (shadows == null) {
                    shadows = Maps.newMapOf(String);
                }
                var shadlist :Array = shadows.get(ccomp.componentClass.shadow);
                if (shadlist == null) {
                    shadows.put(ccomp.componentClass.shadow, shadlist = []);
                }
                shadlist.push(tcomp);
            }
        }

/* TODO - Implement shadows & masks - I don't actually know if/where we use these, though.
        // now create any necessary shadow layers
        if (shadows != null) {
            for (Map.Entry<String, ArrayList<TranslatedComponent>> entry : shadows.entrySet()) {
                ComponentFrames scf = compositeShadow(action, entry.getKey(), entry.getValue());
                if (scf != null) {
                    sources.add(scf);
                }
            }
        }

        // add any necessary masks
        for (ComponentFrames cframes : sources) {
            ArrayList<TranslatedComponent> mcomps = ccomps.get(cframes.ccomp.componentClass.mask);
            if (mcomps != null) {
                cframes.frames = compositeMask(action, cframes.ccomp, cframes.frames, mcomps);
            }
        }
*/
        // use those to create an entity that will lazily composite things
        // together as they are needed
        return new CompositedActionFrames(_frameCache, _actions.get(action), sources);
    }

    protected var _crepo :ComponentRepository;

    protected var _actions :Map = Maps.newMapOf(String);

    protected var _actionFrames :Map = Maps.newMapOf(FrameKey);

    protected var _frameCache :LRMap = new LRMap(Maps.newMapOf(CompositedFramesKey), MAX_FRAMES);

    protected var _charClass :Class;

    protected static const MAX_FRAMES :int = 1000;
}
}

import com.threerings.util.Hashable;
import com.threerings.util.StringUtil;
import com.threerings.cast.CharacterDescriptor;

class FrameKey
    implements Hashable
{
    public var desc :CharacterDescriptor;

    public var action :String;

    public function FrameKey (desc :CharacterDescriptor, action :String)
    {
        this.desc = desc;
        this.action = action;
    }

    public function hashCode () :int
    {
        return desc.hashCode() ^ StringUtil.hashCode(action);
    }

    public function equals (other :Object) :Boolean
    {
        if (other is FrameKey) {
            var okey :FrameKey = FrameKey(other);
            return okey.desc.equals(desc) && okey.action == action;
        } else {
            return false;
        }
    }
}

import flash.geom.Point;

import com.threerings.cast.ActionFrames;
import com.threerings.cast.CharacterComponent;

class TranslatedComponent
{
    public var ccomp :CharacterComponent;
    public var xlation :Point;

    public function TranslatedComponent (ccomp :CharacterComponent, xlation :Point)
    {
        this.ccomp = ccomp;
        this.xlation = xlation;
    }

    public function getFrames (action :String, type :String) :ActionFrames
    {
        var frames :ActionFrames = ccomp.getFrames(action, type);
        return (frames == null || xlation == null) ?
            frames : frames.cloneTranslated(xlation.x, xlation.y);
    }

}

Allow access to getComponent through the character manager rather than having to go through the repository.

git-svn-id: b675b909355d5cf946977f44a8ec5a6ceb3782e4@994 ed5b42cb-e716-0410-a449-f6a68f950b19


// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2011  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
package com.kaltura.delegates {

	import com.kaltura.config.IKalturaConfig;
	import com.kaltura.config.KalturaConfig;
	import com.kaltura.core.KClassFactory;
	import com.kaltura.errors.KalturaError;
	import com.kaltura.events.KalturaEvent;
	import com.kaltura.net.KalturaCall;
	import com.kaltura.encryption.MD5;

	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.HTTPStatusEvent;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.TimerEvent;
	import flash.net.FileReference;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.net.URLRequestMethod;
	import flash.utils.Timer;
	import flash.utils.getDefinitionByName;

	public class WebDelegateBase extends EventDispatcher implements IKalturaCallDelegate {

		public static var CONNECT_TIME:int = 60000; //60 secs
		public static var LOAD_TIME:int = 120000; //120 secs

		protected var connectTimer:Timer;
		protected var loadTimer:Timer;

		protected var _call:KalturaCall;
		protected var _config:KalturaConfig;

		protected var loader:URLLoader;
		protected var fileRef:FileReference;

		//Setters & getters
		public function get call():KalturaCall {
			return _call;
		}

		public function set call(newVal:KalturaCall):void {
			_call = newVal;
		}

		public function get config():IKalturaConfig {
			return _config;
		}

		public function set config(newVal:IKalturaConfig):void {
			_config = newVal as KalturaConfig;
		}

		public function WebDelegateBase(call:KalturaCall = null, config:KalturaConfig = null) {
			this.call = call;
			this.config = config;
			if (!call)
				return; //maybe a multi request
			if (call.useTimeout) {
				connectTimer = new Timer(CONNECT_TIME, 1);
				connectTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onConnectTimeout);

				loadTimer = new Timer(LOAD_TIME, 1);
				loadTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onLoadTimeOut);
			}
			execute();
		}

		public function close():void {
			try {
				loader.close();
			}
			catch (e:*) {
			}

			if (call.useTimeout) {
				connectTimer.stop();
				loadTimer.stop();
			}
		}

		protected function onConnectTimeout(event:TimerEvent):void {
			var kError:KalturaError = new KalturaError();
			kError.errorCode = "KMC_CONNECTION_TIMEOUT";
			kError.errorMsg = "Connection Timeout: " + CONNECT_TIME / 1000 + " sec with no post command from kaltura client.";
			_call.handleError(kError);
			dispatchEvent(new KalturaEvent(KalturaEvent.FAILED, false, false, false, null, kError));

			loadTimer.stop();
			close();
		}

		protected function onLoadTimeOut(event:TimerEvent):void {
			connectTimer.stop();

			close();

			var kError:KalturaError = new KalturaError();
			kError.errorCode = "KMC_POST_TIMEOUT";
			kError.errorMsg = "Post Timeout: " + LOAD_TIME / 1000 + " sec with no post result.";
			_call.handleError(kError);
			dispatchEvent(new KalturaEvent(KalturaEvent.FAILED, false, false, false, null, kError));
		}

		protected function execute():void {
			if (call == null) {
				throw new Error('No call defined.');
			}
			post(); //post the call
		}

		/**
		* Helper function for sending the call straight to the server
		*/
		protected function post():void {

			addOptionalArguments();

			formatRequest();

			sendRequest();

			if (call.useTimeout) {
				connectTimer.start();
			}
		}

		protected function formatRequest():void {
			//The configuration is stronger then the args
			if (_config.partnerId != null && _call.args["partnerId"] == -1)
				_call.setRequestArgument("partnerId", _config.partnerId);

			if (_config.ks != null)
				_call.setRequestArgument("ks", _config.ks);

			if (_config.clientTag != null)
				_call.setRequestArgument("clientTag", _config.clientTag);

			_call.setRequestArgument("ignoreNull", _config.ignoreNull);

			//Create signature hash.
			//call.setRequestArgument("kalsig", getMD5Checksum(call));
		}

		protected function getMD5Checksum(call:KalturaCall):String {
			var props:Array = new Array();
			for each (var prop:String in call.args)
				props.push(prop);

			props.push("service");
			props.push("action");
			props.sort();

			var s:String;
			for each (prop in props) {
				s += prop;

				if (prop == "service")
					s += call.service;
				else if (prop == "action")
					s += call.action;
				else
					s += call.args[prop];
			}

			return MD5.encrypt(s);
		}

		protected function sendRequest():void {

			//construct the loader
			createURLLoader();

			//Create signature hash.
			var kalsig:String = getMD5Checksum(call);

			//create the service request for normal calls
			var url:String = _config.protocol + _config.domain + "/" + _config.srvUrl + "?service=" + call.service + "&action=" + call.action + "&kalsig=" + kalsig;;

			if (_call.method == URLRequestMethod.GET)
				url += "&";

			var req:URLRequest = new URLRequest(url);
			req.contentType = "application/x-www-form-urlencoded";
			req.method = call.method;
			req.data = call.args;

			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.load(req);
		}

		protected function createURLLoader():void {
			loader = new URLLoader();
			loader.addEventListener(Event.COMPLETE, onDataComplete);
			loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, onHTTPStatus);
			loader.addEventListener(IOErrorEvent.IO_ERROR, onError);
			loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
			loader.addEventListener(Event.OPEN, onOpen);
		}

		protected function onHTTPStatus(event:HTTPStatusEvent):void {
		}

		protected function onOpen(event:Event):void {
			if (call.useTimeout) {
				connectTimer.stop();
				loadTimer.start();
			}
		}

		protected function addOptionalArguments():void {
			//add optional args here
		}

		// Event Handlers
		protected function onDataComplete(event:Event):void {
			try {
				handleResult(XML(event.target.data));
			}
			catch (e:Error) {
				var kErr:KalturaError = new KalturaError();
				kErr.errorCode = String(e.errorID);
				kErr.errorMsg = e.message;
				_call.handleError(kErr);
			}
		}

		protected function onError(event:ErrorEvent):void {
			clean();
			var kError:KalturaError = createKalturaError(event, loader.data);

			if (!kError) {
				kError.errorMsg = event.text;
					//kError.errorCode;
			}

			call.handleError(kError);

			dispatchEvent(new KalturaEvent(KalturaEvent.FAILED, false, false, false, null, kError));
		}

		/**
		* parse the server's response and let the call process it.
		 * @param result  server's response
		*/
		protected function handleResult(result:XML):void {
			clean();

			var error:KalturaError = validateKalturaResponse(result);

			if (error == null) {
				var digestedResult:Object = parse(result);
				call.handleResult(digestedResult);
			}
			else {
				call.handleError(error);
			}
		}

		/**
		* stop timers and clean event listeners
		 */
		protected function clean():void {
			if (call.useTimeout) {
				connectTimer.stop();
				loadTimer.stop();
			}

			if (loader == null) {
				return;
			}

			loader.removeEventListener(Event.COMPLETE, onDataComplete);
			loader.removeEventListener(IOErrorEvent.IO_ERROR, onError);
			loader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
			loader.removeEventListener(Event.OPEN, onOpen);
		}

		/**
		* create the correct object and populate it with the given values. if the needed class is not found
		 * in the file, a generic object is created with attributes matching the XML attributes.
		* Override this parssing function in the specific delegate to create the correct object.
		* @param   result      instance attributes
		* @return an instance of the class declared by the given XML.
		* */
		public function parse(result:XML):* {
			//by defualt create the response object
			var cls:Class;
			try {
				cls = getDefinitionByName('com.kaltura.vo.' + result.result.objectType) as Class;
			}
			catch (e:Error) {
				cls = Object;
			}
			var obj:* = (new KClassFactory(cls)).newInstanceFromXML(result.result);
			return obj;
		}

		/**
		* If the result string holds an error, return a KalturaError object with
		 * relevant values. <br/>
		* Overide this to create validation object and fill it.
		* @param result  the string returned from the server.
		* @return  matching error object
		 */
		protected function validateKalturaResponse(result:String):KalturaError {
			var kError:KalturaError = null;
			var xml:XML = XML(result);
			if (xml.result.hasOwnProperty('error')) {
				kError = new KalturaError();
				kError.errorCode = String(xml.result.error.code);
				kError.errorMsg = xml.result.error.message;
				dispatchEvent(new KalturaEvent(KalturaEvent.FAILED, false, false, false, null, kError));
			}

			return kError;
		}

		//Overide this to create error object and fill it
		protected function createKalturaError(event:ErrorEvent, loaderData:*):KalturaError {
			var ke:KalturaError = new KalturaError();
			return ke;
		}

		/**
		* create the url that is used for serve actions
		* @param call    the KalturaCall that defines the required parameters
		 * @return URLRequest with relevant parameters
		* */
		public function getServeUrl(call:KalturaCall):URLRequest {
			var url:String = _config.protocol + _config.domain + "/" + _config.srvUrl + "?service=" + call.service + "&action=" + call.action;
			for (var key:String in call.args) {
				url += "&" + key + "=" + call.args[key];
			}
			var req:URLRequest = new URLRequest(url);
			req.contentType = "application/x-www-form-urlencoded";
			req.method = call.method;
//          req.data = call.args;
			return req;
		}

	}
}

// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2011  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
package com.kaltura.delegates {

	import com.kaltura.config.IKalturaConfig;
	import com.kaltura.config.KalturaConfig;
	import com.kaltura.core.KClassFactory;
	import com.kaltura.errors.KalturaError;
	import com.kaltura.events.KalturaEvent;
	import com.kaltura.net.KalturaCall;
	import com.kaltura.encryption.MD5;

	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.HTTPStatusEvent;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.TimerEvent;
	import flash.net.FileReference;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.net.URLRequestMethod;
	import flash.utils.Timer;
	import flash.utils.getDefinitionByName;

	public class WebDelegateBase extends EventDispatcher implements IKalturaCallDelegate {

		public static var CONNECT_TIME:int = 60000; //60 secs
		public static var LOAD_TIME:int = 120000; //120 secs

		protected var connectTimer:Timer;
		protected var loadTimer:Timer;

		protected var _call:KalturaCall;
		protected var _config:KalturaConfig;

		protected var loader:URLLoader;
		protected var fileRef:FileReference;

		//Setters & getters
		public function get call():KalturaCall {
			return _call;
		}

		public function set call(newVal:KalturaCall):void {
			_call = newVal;
		}

		public function get config():IKalturaConfig {
			return _config;
		}

		public function set config(newVal:IKalturaConfig):void {
			_config = newVal as KalturaConfig;
		}

		public function WebDelegateBase(call:KalturaCall = null, config:KalturaConfig = null) {
			this.call = call;
			this.config = config;
			if (!call)
				return; //maybe a multi request
			if (call.useTimeout) {
				connectTimer = new Timer(CONNECT_TIME, 1);
				connectTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onConnectTimeout);

				loadTimer = new Timer(LOAD_TIME, 1);
				loadTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onLoadTimeOut);
			}
			execute();
		}

		public function close():void {
			try {
				loader.close();
			}
			catch (e:*) {
			}

			if (call.useTimeout) {
				connectTimer.stop();
				loadTimer.stop();
			}
		}

		protected function onConnectTimeout(event:TimerEvent):void {
			var kError:KalturaError = new KalturaError();
			kError.errorCode = "CONNECTION_TIMEOUT";
			kError.errorMsg = "Connection Timeout: " + CONNECT_TIME / 1000 + " sec with no post command from kaltura client.";
			_call.handleError(kError);
			dispatchEvent(new KalturaEvent(KalturaEvent.FAILED, false, false, false, null, kError));

			loadTimer.stop();
			close();
		}

		protected function onLoadTimeOut(event:TimerEvent):void {
			connectTimer.stop();

			close();

			var kError:KalturaError = new KalturaError();
			kError.errorCode = "POST_TIMEOUT";
			kError.errorMsg = "Post Timeout: " + LOAD_TIME / 1000 + " sec with no post result.";
			_call.handleError(kError);
			dispatchEvent(new KalturaEvent(KalturaEvent.FAILED, false, false, false, null, kError));
		}

		protected function execute():void {
			if (call == null) {
				throw new Error('No call defined.');
			}
			post(); //post the call
		}

		/**
		* Helper function for sending the call straight to the server
		*/
		protected function post():void {

			addOptionalArguments();

			formatRequest();

			sendRequest();

			if (call.useTimeout) {
				connectTimer.start();
			}
		}

		protected function formatRequest():void {
			//The configuration is stronger then the args
			if (_config.partnerId != null && _call.args["partnerId"] == -1)
				_call.setRequestArgument("partnerId", _config.partnerId);

			if (_config.ks != null)
				_call.setRequestArgument("ks", _config.ks);

			if (_config.clientTag != null)
				_call.setRequestArgument("clientTag", _config.clientTag);

			_call.setRequestArgument("ignoreNull", _config.ignoreNull);

			//Create signature hash.
			//call.setRequestArgument("kalsig", getMD5Checksum(call));
		}

		protected function getMD5Checksum(call:KalturaCall):String {
			var props:Array = new Array();
			for each (var prop:String in call.args)
				props.push(prop);

			props.push("service");
			props.push("action");
			props.sort();

			var s:String;
			for each (prop in props) {
				s += prop;

				if (prop == "service")
					s += call.service;
				else if (prop == "action")
					s += call.action;
				else
					s += call.args[prop];
			}

			return MD5.encrypt(s);
		}

		protected function sendRequest():void {

			//construct the loader
			createURLLoader();

			//Create signature hash.
			var kalsig:String = getMD5Checksum(call);

			//create the service request for normal calls
			var url:String = _config.protocol + _config.domain + "/" + _config.srvUrl + "?service=" + call.service + "&action=" + call.action + "&kalsig=" + kalsig;;

			if (_call.method == URLRequestMethod.GET)
				url += "&";

			var req:URLRequest = new URLRequest(url);
			req.contentType = "application/x-www-form-urlencoded";
			req.method = call.method;
			req.data = call.args;

			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.load(req);
		}

		protected function createURLLoader():void {
			loader = new URLLoader();
			loader.addEventListener(Event.COMPLETE, onDataComplete);
			loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, onHTTPStatus);
			loader.addEventListener(IOErrorEvent.IO_ERROR, onError);
			loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
			loader.addEventListener(Event.OPEN, onOpen);
		}

		protected function onHTTPStatus(event:HTTPStatusEvent):void {
		}

		protected function onOpen(event:Event):void {
			if (call.useTimeout) {
				connectTimer.stop();
				loadTimer.start();
			}
		}

		protected function addOptionalArguments():void {
			//add optional args here
		}

		// Event Handlers
		protected function onDataComplete(event:Event):void {
			try {
				handleResult(XML(event.target.data));
			}
			catch (e:Error) {
				var kErr:KalturaError = new KalturaError();
				kErr.errorCode = String(e.errorID);
				kErr.errorMsg = e.message;
				_call.handleError(kErr);
			}
		}

		protected function onError(event:ErrorEvent):void {
			clean();
			var kError:KalturaError = createKalturaError(event, loader.data);

			if (!kError) {
				kError.errorMsg = event.text;
					//kError.errorCode;
			}

			call.handleError(kError);

			dispatchEvent(new KalturaEvent(KalturaEvent.FAILED, false, false, false, null, kError));
		}

		/**
		* parse the server's response and let the call process it.
		 * @param result  server's response
		*/
		protected function handleResult(result:XML):void {
			clean();

			var error:KalturaError = validateKalturaResponse(result);

			if (error == null) {
				var digestedResult:Object = parse(result);
				call.handleResult(digestedResult);
			}
			else {
				call.handleError(error);
			}
		}

		/**
		* stop timers and clean event listeners
		 */
		protected function clean():void {
			if (call.useTimeout) {
				connectTimer.stop();
				loadTimer.stop();
			}

			if (loader == null) {
				return;
			}

			loader.removeEventListener(Event.COMPLETE, onDataComplete);
			loader.removeEventListener(IOErrorEvent.IO_ERROR, onError);
			loader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
			loader.removeEventListener(Event.OPEN, onOpen);
		}

		/**
		* create the correct object and populate it with the given values. if the needed class is not found
		 * in the file, a generic object is created with attributes matching the XML attributes.
		* Override this parssing function in the specific delegate to create the correct object.
		* @param   result      instance attributes
		* @return an instance of the class declared by the given XML.
		* */
		public function parse(result:XML):* {
			//by defualt create the response object
			var cls:Class;
			try {
				cls = getDefinitionByName('com.kaltura.vo.' + result.result.objectType) as Class;
			}
			catch (e:Error) {
				cls = Object;
			}
			var obj:* = (new KClassFactory(cls)).newInstanceFromXML(result.result);
			return obj;
		}

		/**
		* If the result string holds an error, return a KalturaError object with
		 * relevant values. <br/>
		* Overide this to create validation object and fill it.
		* @param result  the string returned from the server.
		* @return  matching error object
		 */
		protected function validateKalturaResponse(result:String):KalturaError {
			var kError:KalturaError = null;
			var xml:XML = XML(result);
			if (xml.result.hasOwnProperty('error')) {
				kError = new KalturaError();
				kError.errorCode = String(xml.result.error.code);
				kError.errorMsg = xml.result.error.message;
				dispatchEvent(new KalturaEvent(KalturaEvent.FAILED, false, false, false, null, kError));
			}

			return kError;
		}

		//Overide this to create error object and fill it
		protected function createKalturaError(event:ErrorEvent, loaderData:*):KalturaError {
			var ke:KalturaError = new KalturaError();
			return ke;
		}

		/**
		* create the url that is used for serve actions
		* @param call    the KalturaCall that defines the required parameters
		 * @return URLRequest with relevant parameters
		* */
		public function getServeUrl(call:KalturaCall):URLRequest {
			var url:String = _config.protocol + _config.domain + "/" + _config.srvUrl + "?service=" + call.service + "&action=" + call.action;
			for (var key:String in call.args) {
				url += "&" + key + "=" + call.args[key];
			}
			var req:URLRequest = new URLRequest(url);
			req.contentType = "application/x-www-form-urlencoded";
			req.method = call.method;
//          req.data = call.args;
			return req;
		}

	}
}

change error code (no "KMC")

qnd: change error code (no "KMC")

git-svn-id: 8a2ccb88241e16c78017770bc38d91d6d5396a5a@86268 6b8eccd3-e8c5-4e7d-8186-e12b5326b719


/*
 * Copyright 2009 Ryan Berdeen. All rights reserved.
 * Distributed under the terms of the MIT License.
 * See accompanying file LICENSE.txt
 */

package com.ryanberdeen.echonest.api.v3 {
  import flash.events.Event;
  import flash.events.HTTPStatusEvent;
  import flash.events.IOErrorEvent;
  import flash.events.ProgressEvent;
  import flash.events.SecurityErrorEvent;
  import flash.net.URLLoader;
  import flash.net.URLRequest;
  import flash.net.URLRequestHeader;
  import flash.net.URLVariables;

  /**
  * Base class for Echo Nest API classes.
  */
  public class ApiSupport {
    public static const API_VERSION:int = 3;
    /**
    * @private
    */
    protected var _baseUrl:String = 'http://developer.echonest.com/api/';

    /**
    * @private
    */
    protected var _apiKey:String;

    /**
    * The API key to use for Echo Nest API requests.
    */
    public function set apiKey(apiKey:String):void {
      _apiKey = apiKey;
    }

    /**
    * Creates a request for an Echo Nest API method call with a set of
    * parameters.
    *
    * @param method The method to call.
    * @param parameters The parameters to include in the request.
    *
    * @return The request to use to call the method.
    */
    public function createRequest(method:String, parameters:Object):URLRequest {
      var variables:URLVariables = new URLVariables;
      variables.api_key = _apiKey;
      variables.version = API_VERSION;
      for (var name:String in parameters) {
        variables[name] = parameters[name];
      }

      var request:URLRequest = new URLRequest();
      request.url = _baseUrl + method;
      request.data = variables;
      request.requestHeaders = new Array(new URLRequestHeader('X-User-Agent', 'echo-nest-flash-api'));

      return request;
    }

    /**
    * Creates a loader with event listeners.
    *
    *
The following options are supported:

    *
    *

Option	Event

    *

    *     onComplete
    *     Event.COMPLETE
    *

    *

    *     onResponse
    *     Called with the processed response.
    *

    *

    *     onEchoNestError
    *     Called with an EchoNestError if the status code is nonzero
    *

    *

    *     onProgress
    *     ProgressEvent.PROGRESS
    *

    *

    *     onSecurityError
    *     SecurityErrorEvent.SECURITY_ERROR
    *

    *

    *     onIoError
    *     IOErrorEvent.IO_ERROR
    *

    *

    *     onError
    *     IOErrorEvent.IO_ERROR
 SecurityErrorEvent.SECURITY_ERROR
    *

    *

    *     onHttpStatus
    *     HTTPStatusEvent.HTTP_STATUS
    *

    *

    *
    * @param options The event listener options.
    * @param responseProcessor The function that processes the XML response.
    */
    public function createLoader(options:Object, responseProcessor:Function = null, ...responseProcessorArgs):URLLoader {
      var loader:URLLoader = new URLLoader();

      if (options.onComplete) {
        loader.addEventListener(Event.COMPLETE, options.onComplete);
      }

      if (responseProcessor != null && options.onResponse) {
        loader.addEventListener(Event.COMPLETE, function(e:Event):void {
          try {
            var responseXml:XML = new XML(loader.data);
            checkStatus(responseXml);
            responseProcessorArgs.push(responseXml);
            var response:Object = responseProcessor.apply(responseProcessor, responseProcessorArgs);
            options.onResponse(response);
          }
          catch (e:EchoNestError) {
            if (options.onEchoNestError) {
              options.onEchoNestError(e);
            }
          }
        });
      }

      if (options.onProgress) {
        loader.addEventListener(ProgressEvent.PROGRESS, options.onProgress);
      }

      if (options.onSecurityError) {
        loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, options.onSecurityError);
      }

      if (options.onIoError) {
        loader.addEventListener(IOErrorEvent.IO_ERROR, options.onIoError);
      }

      if (options.onError) {
        loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, options.onError);
        loader.addEventListener(IOErrorEvent.IO_ERROR, options.onError);
      }

      if (options.onHttpStatus) {
        loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, options.onHttpStatus);
      }

      return loader;
    }

    /**
    * Throws an EchoNestError if the status indicates an error.
    *
    * @param The XML result of an Echo Nest API call.
    *
    * @throws EchoNestError When the status code is nonzero.
    */
    public function checkStatus(response:XML):void {
      if (response.status.code != 0) {
        throw new EchoNestError(response.status.code, response.status.message);
      }
    }
  }
}

/*
 * Copyright 2009 Ryan Berdeen. All rights reserved.
 * Distributed under the terms of the MIT License.
 * See accompanying file LICENSE.txt
 */

package com.ryanberdeen.echonest.api.v3 {
  import flash.events.Event;
  import flash.events.HTTPStatusEvent;
  import flash.events.IOErrorEvent;
  import flash.events.ProgressEvent;
  import flash.events.SecurityErrorEvent;
  import flash.net.URLLoader;
  import flash.net.URLRequest;
  import flash.net.URLRequestHeader;
  import flash.net.URLVariables;

  /**
  * Base class for Echo Nest API classes.
  */
  public class ApiSupport {
    public static const API_VERSION:int = 3;
    /**
    * @private
    */
    protected var _baseUrl:String = 'http://developer.echonest.com/api/';

    /**
    * @private
    */
    protected var _apiKey:String;

    /**
    * The API key to use for Echo Nest API requests.
    */
    public function set apiKey(apiKey:String):void {
      _apiKey = apiKey;
    }

    /**
    * Creates a request for an Echo Nest API method call with a set of
    * parameters.
    *
    * @param method The method to call.
    * @param parameters The parameters to include in the request.
    *
    * @return The request to use to call the method.
    */
    public function createRequest(method:String, parameters:Object):URLRequest {
      var variables:URLVariables = new URLVariables;
      variables.api_key = _apiKey;
      variables.version = API_VERSION;
      for (var name:String in parameters) {
        variables[name] = parameters[name];
      }

      var request:URLRequest = new URLRequest();
      request.url = _baseUrl + method;
      request.data = variables;

      return request;
    }

    /**
    * Creates a loader with event listeners.
    *
    *
The following options are supported:

    *
    *

Option	Event

    *

    *     onComplete
    *     Event.COMPLETE
    *

    *

    *     onResponse
    *     Called with the processed response.
    *

    *

    *     onEchoNestError
    *     Called with an EchoNestError if the status code is nonzero
    *

    *

    *     onProgress
    *     ProgressEvent.PROGRESS
    *

    *

    *     onSecurityError
    *     SecurityErrorEvent.SECURITY_ERROR
    *

    *

    *     onIoError
    *     IOErrorEvent.IO_ERROR
    *

    *

    *     onError
    *     IOErrorEvent.IO_ERROR
 SecurityErrorEvent.SECURITY_ERROR
    *

    *

    *     onHttpStatus
    *     HTTPStatusEvent.HTTP_STATUS
    *

    *

    *
    * @param options The event listener options.
    * @param responseProcessor The function that processes the XML response.
    */
    public function createLoader(options:Object, responseProcessor:Function = null, ...responseProcessorArgs):URLLoader {
      var loader:URLLoader = new URLLoader();

      if (options.onComplete) {
        loader.addEventListener(Event.COMPLETE, options.onComplete);
      }

      if (responseProcessor != null && options.onResponse) {
        loader.addEventListener(Event.COMPLETE, function(e:Event):void {
          try {
            var responseXml:XML = new XML(loader.data);
            checkStatus(responseXml);
            responseProcessorArgs.push(responseXml);
            var response:Object = responseProcessor.apply(responseProcessor, responseProcessorArgs);
            options.onResponse(response);
          }
          catch (e:EchoNestError) {
            if (options.onEchoNestError) {
              options.onEchoNestError(e);
            }
          }
        });
      }

      if (options.onProgress) {
        loader.addEventListener(ProgressEvent.PROGRESS, options.onProgress);
      }

      if (options.onSecurityError) {
        loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, options.onSecurityError);
      }

      if (options.onIoError) {
        loader.addEventListener(IOErrorEvent.IO_ERROR, options.onIoError);
      }

      if (options.onError) {
        loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, options.onError);
        loader.addEventListener(IOErrorEvent.IO_ERROR, options.onError);
      }

      if (options.onHttpStatus) {
        loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, options.onHttpStatus);
      }

      return loader;
    }

    /**
    * Throws an EchoNestError if the status indicates an error.
    *
    * @param The XML result of an Echo Nest API call.
    *
    * @throws EchoNestError When the status code is nonzero.
    */
    public function checkStatus(response:XML):void {
      if (response.status.code != 0) {
        throw new EchoNestError(response.status.code, response.status.message);
      }
    }
  }
}

remove request header

remove request header


package dolly.data {
import mx.collections.ArrayCollection;
import mx.collections.ArrayList;

[Cloneable]
public class CompositeCloneableClass {

	public var cloneable:CloneableClass = new CloneableClass();

	public var array:Array = [0, 1, 2, 3, 4];

	public var arrayList:ArrayList = new ArrayList([0, 1, 2, 3, 4]);

	public var arrayCollection:ArrayCollection = new ArrayCollection([0, 1, 2, 3, 4]);

	public function CompositeCloneableClass() {
	}
}
}

package dolly.data {
import mx.collections.ArrayCollection;
import mx.collections.ArrayList;

[Cloneable]
public class CompositeCloneableClass {

	public var cloneable:CloneableClass;

	public var array:Array = [0, 1, 2, 3, 4];

	public var arrayList:ArrayList = new ArrayList([0, 1, 2, 3, 4]);

	public var arrayCollection:ArrayCollection = new ArrayCollection([0, 1, 2, 3, 4]);

	public function CompositeCloneableClass() {
	}
}
}

Remove default instantiation of CompositeCloneableClass.cloneable field.