package {
  import flash.display.*;
  import flash.events.*;
  import flash.text.*;
  import flash.ui.Mouse;
  import flash.notifications.NotificationStyle;
  import com.juankpro.ane.localnotif.*;

  [SWF(backgroundColor="#FFFFFF", width="320", height="480", frameRate="30")]
  public class Sample extends Sprite {

    private var notificationManager:NotificationManager;

    private var postButton:SimpleButton;
    private var cancelButton:SimpleButton;
    private var codeButton:SimpleButton;
    private var badgeButton:SimpleButton;
    private var notificationTF:TextField;
    private var contentsScaleFactor:int = 2;

    private static const NOTIFICATION_CODE:String = "NOTIFICATION_CODE_001";

    public function Sample() {
      addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
    }

    private function addedToStageHandler(event:Event):void {
      stage.align = StageAlign.TOP_LEFT;
      stage.scaleMode = StageScaleMode.NO_SCALE;
      stage.quality = StageQuality.BEST;

      stage.addEventListener(Event.RESIZE, resizeHandler);
    }

    private var initialized:Boolean = false;

    private function resizeHandler(event:Event):void {
      initApp();
      printMessage("Resized");
    }

    private function initApp():void {
      if (initialized) return;
      initialized = true;

      if (NotificationManager.isSupported) {
        notificationManager = new NotificationManager();

        if (NotificationManager.needsSubsciption) {
          var options:LocalNotifierSubscribeOptions = new LocalNotifierSubscribeOptions();
          options.notificationStyles = NotificationManager.supportedNotificationStyles;
          notificationManager.addEventListener(NotificationEvent.SETTINGS_SUBSCRIBED,
                                               settingsSubscribedHandler);
          notificationManager.subscribe(options);
        }
      }

      initUI();
      registerEvents();
    }

    private function settingsSubscribedHandler(event:NotificationEvent):void {
      printMessage("Settings: " + event.subscribeOptions.notificationStyles.join("\n"));
      registerEvents();
    }

    private function initUI():void {
      var top1:int = 20 * contentsScaleFactor;
      var top2:int = 80 * contentsScaleFactor;
      postButton = createButton("Post", 0, top1);
      cancelButton = createButton("Cancel", stage.stageWidth - 100 * contentsScaleFactor, top1);
      codeButton = createButton("By Code", 0, top2);
      badgeButton = createButton("Clear Badge", stage.stageWidth - 100 * contentsScaleFactor, top2);

      addChild(postButton);
      addChild(cancelButton);
      addChild(codeButton);
      addChild(badgeButton);

      notificationTF = createTextField(0, int(stage.stageHeight / 2),
         stage.stageWidth - 1, int(stage.stageHeight / 2) - 1);
      notificationTF.border = true;
      addChild(notificationTF);
    }

    private function printMessage(message:String, title:String = null):void {
      notificationTF.text += "-----\n" + (title? title + "\n" : "") + message + "\n";
      notificationTF.scrollV = notificationTF.maxScrollV;
    }

    private function registerEvents():void {
      notificationManager.addEventListener(NotificationEvent.NOTIFICATION_ACTION, notificationActionHandler);
      postButton.addEventListener(MouseEvent.CLICK, buttonClickHandler);
      cancelButton.addEventListener(MouseEvent.CLICK, buttonClickHandler);
      codeButton.addEventListener(MouseEvent.CLICK, buttonClickHandler);
      badgeButton.addEventListener(MouseEvent.CLICK, buttonClickHandler);
    }

    private function buttonClickHandler(event:MouseEvent):void {
      switch(event.target) {
        case postButton:
          var notification:Notification = new Notification();
          notification.title = "Sample Title";
          notification.body = "Body sample";
          notification.actionLabel = "Rumble";
          notification.soundName = "fx05.caf";
          notification.fireDate = new Date((new Date()).time + (15 * 1000));
          notification.numberAnnotation = 3;
          notification.actionData = {sampleData:"Hello World!"};

          notificationManager.notifyUser(NOTIFICATION_CODE, notification);
          printNotification('Posted Message', notification);
          break;
        case cancelButton:
          notificationManager.cancelAll();
          printMessage("Cancelled all notifications");
          break;
        case codeButton:
          notificationManager.cancel(NOTIFICATION_CODE);
          printMessage("Cancelled notification with code " + NOTIFICATION_CODE);
          break;
        case badgeButton:
          notificationManager.applicationBadgeNumber = 0;
          printMessage("Reset badge number to zero");
          break;
      }
    }

    private function printNotification(title:String, notification:Notification):void {
      printMessage(
        '\nTitle: ' + notification.title +
        '\nBody: ' + notification.body +
        '\nAction: ' + notification.actionLabel +
        '\nCode: ' + NOTIFICATION_CODE +
        '\nData: {' + notification.actionData.sampleData + '}' +
        '\nAnnotation: ' + notification.numberAnnotation +
        '\nfireDate: ' + notification.fireDate +
        '\nsoundName: ' + notification.soundName,
        title);
    }

    private function notificationActionHandler(event:NotificationEvent):void {
      printMessage("Code: " + event.notificationCode +
        "\nSample Data: {" + event.actionData.sampleData + "}",
        "Received notification");
    }

    private function createTextField(x:int, y:int, width:int, height:int):TextField {
      var textField:TextField = new TextField();
      textField.width = width;
      textField.height = height;
      textField.x = x;
      textField.y = y;

      var tf:TextFormat = textField.getTextFormat();
      tf.font = '_sans';
      tf.size = 14 * contentsScaleFactor;

      textField.defaultTextFormat = tf;
      textField.setTextFormat(tf);

      return textField;
    }

    private function createButton(label:String, x:int, y:int):SimpleButton {
      var button:SimpleButton = new SimpleButton();
      var w:int = 100 * contentsScaleFactor;
      var h:int = 30 * contentsScaleFactor;

      var buttonSprite:Sprite = new Sprite();
      buttonSprite.graphics.lineStyle(1, 0x555555);
      buttonSprite.graphics.beginFill(0xff000, 1);
      buttonSprite.graphics.drawRect(0, 0, w, h);
      buttonSprite.graphics.endFill();

      var buttonLabel:TextField = createTextField(0, 8 * contentsScaleFactor, w, h);

      var tf:TextFormat = buttonLabel.getTextFormat();
      tf.align = TextFormatAlign.CENTER;
      tf.font = "Helvetica";
      tf.size = 14 * contentsScaleFactor;

      buttonLabel.defaultTextFormat = tf;
      buttonLabel.setTextFormat(tf);

      buttonLabel.text = label;
      buttonSprite.addChild(buttonLabel);

      button.x = x;
      button.y = y;
      button.overState = button.downState = button.upState = button.hitTestState = buttonSprite;
      return button;
    }
  }
}

package {
  import flash.display.*;
  import flash.events.*;
  import flash.text.*;
  import flash.ui.Mouse;
  import flash.notifications.NotificationStyle;
  import com.juankpro.ane.localnotif.*;

  [SWF(backgroundColor="#FFFFFF", width="320", height="480", frameRate="30")]
  public class Sample extends Sprite {

    private var notificationManager:NotificationManager;

    private var postButton:SimpleButton;
    private var cancelButton:SimpleButton;
    private var codeButton:SimpleButton;
    private var badgeButton:SimpleButton;
    private var clearButton:SimpleButton;
    private var notificationTF:TextField;
    private var contentsScaleFactor:int = 2;

    private static const NOTIFICATION_CODE:String = "NOTIFICATION_CODE_001";

    public function Sample() {
      addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
    }

    private function addedToStageHandler(event:Event):void {
      stage.align = StageAlign.TOP_LEFT;
      stage.scaleMode = StageScaleMode.NO_SCALE;
      stage.quality = StageQuality.BEST;

      stage.addEventListener(Event.RESIZE, resizeHandler);
    }

    private var initialized:Boolean = false;

    private function resizeHandler(event:Event):void {
      initApp();
      printMessage("Resized");
    }

    private function initApp():void {
      if (initialized) return;
      initialized = true;

      if (NotificationManager.isSupported) {
        notificationManager = new NotificationManager();

        if (NotificationManager.needsSubsciption) {
          var options:LocalNotifierSubscribeOptions = new LocalNotifierSubscribeOptions();
          options.notificationStyles = NotificationManager.supportedNotificationStyles;
          notificationManager.addEventListener(NotificationEvent.SETTINGS_SUBSCRIBED,
                                               settingsSubscribedHandler);
          notificationManager.subscribe(options);
        }
      }

      initUI();
      registerEvents();
    }

    private function settingsSubscribedHandler(event:NotificationEvent):void {
      printMessage("Settings: " + event.subscribeOptions.notificationStyles.join("\n"));
      registerEvents();
    }

    private function initUI():void {
      var top1:int = 20 * contentsScaleFactor;
      var top2:int = 80 * contentsScaleFactor;
      postButton = createButton("Post", 0, top1);
      cancelButton = createButton("Cancel", stage.stageWidth - 100 * contentsScaleFactor, top1);
      codeButton = createButton("By Code", 0, top2);
      badgeButton = createButton("Clear Badge", stage.stageWidth - 100 * contentsScaleFactor, top2);
      clearButton = createButton("Clear", 0, int(stage.stageHeight / 2) - 30 * contentsScaleFactor);

      addChild(postButton);
      addChild(cancelButton);
      addChild(codeButton);
      addChild(badgeButton);
      addChild(clearButton);

      notificationTF = createTextField(0, int(stage.stageHeight / 2),
         stage.stageWidth - 1, int(stage.stageHeight / 2) - 1);
      notificationTF.border = true;
      addChild(notificationTF);
    }

    private function printMessage(message:String, title:String = null):void {
      notificationTF.text += "-----\n" + (title? title + "\n" : "") + message + "\n";
      notificationTF.scrollV = notificationTF.maxScrollV;
    }

    private function clearMessages():void {
      notificationTF.text = "";
    }

    private function registerEvents():void {
      notificationManager.addEventListener(NotificationEvent.NOTIFICATION_ACTION, notificationActionHandler);
      postButton.addEventListener(MouseEvent.CLICK, buttonClickHandler);
      cancelButton.addEventListener(MouseEvent.CLICK, buttonClickHandler);
      codeButton.addEventListener(MouseEvent.CLICK, buttonClickHandler);
      badgeButton.addEventListener(MouseEvent.CLICK, buttonClickHandler);
    }

    private function buttonClickHandler(event:MouseEvent):void {
      switch(event.target) {
        case postButton:
          var notification:Notification = new Notification();
          notification.title = "Sample Title";
          notification.body = "Body sample";
          notification.actionLabel = "Rumble";
          notification.soundName = "fx05.caf";
          notification.fireDate = new Date((new Date()).time + (15 * 1000));
          notification.numberAnnotation = 3;
          notification.actionData = {sampleData:"Hello World!"};

          notificationManager.notifyUser(NOTIFICATION_CODE, notification);
          printNotification('Posted Message', notification);
          break;
        case cancelButton:
          notificationManager.cancelAll();
          printMessage("Cancelled all notifications");
          break;
        case codeButton:
          notificationManager.cancel(NOTIFICATION_CODE);
          printMessage("Cancelled notification with code " + NOTIFICATION_CODE);
          break;
        case badgeButton:
          notificationManager.applicationBadgeNumber = 0;
          printMessage("Reset badge number to zero");
          break;
        case clearButton:
          clearMessages();
          break;
      }
    }

    private function printNotification(title:String, notification:Notification):void {
      printMessage(
        '\nTitle: ' + notification.title +
        '\nBody: ' + notification.body +
        '\nAction: ' + notification.actionLabel +
        '\nCode: ' + NOTIFICATION_CODE +
        '\nData: {' + notification.actionData.sampleData + '}' +
        '\nAnnotation: ' + notification.numberAnnotation +
        '\nfireDate: ' + notification.fireDate +
        '\nsoundName: ' + notification.soundName,
        title);
    }

    private function notificationActionHandler(event:NotificationEvent):void {
      printMessage("Code: " + event.notificationCode +
        "\nSample Data: {" + event.actionData.sampleData + "}",
        "Received notification");
    }

    private function createTextField(x:int, y:int, width:int, height:int):TextField {
      var textField:TextField = new TextField();
      textField.width = width;
      textField.height = height;
      textField.x = x;
      textField.y = y;

      var tf:TextFormat = textField.getTextFormat();
      tf.font = '_sans';
      tf.size = 14 * contentsScaleFactor;

      textField.defaultTextFormat = tf;
      textField.setTextFormat(tf);

      return textField;
    }

    private function createButton(label:String, x:int, y:int):SimpleButton {
      var button:SimpleButton = new SimpleButton();
      var w:int = 100 * contentsScaleFactor;
      var h:int = 30 * contentsScaleFactor;

      var buttonSprite:Sprite = new Sprite();
      buttonSprite.graphics.lineStyle(1, 0x555555);
      buttonSprite.graphics.beginFill(0xff000, 1);
      buttonSprite.graphics.drawRect(0, 0, w, h);
      buttonSprite.graphics.endFill();

      var buttonLabel:TextField = createTextField(0, 8 * contentsScaleFactor, w, h);

      var tf:TextFormat = buttonLabel.getTextFormat();
      tf.align = TextFormatAlign.CENTER;
      tf.font = "Helvetica";
      tf.size = 14 * contentsScaleFactor;

      buttonLabel.defaultTextFormat = tf;
      buttonLabel.setTextFormat(tf);

      buttonLabel.text = label;
      buttonSprite.addChild(buttonLabel);

      button.x = x;
      button.y = y;
      button.overState = button.downState = button.upState = button.hitTestState = buttonSprite;
      return button;
    }
  }
}

Add clear button to sample

Add clear button to sample


package dolly {

import dolly.core.dolly_internal;
import dolly.data.CloneableClass;
import dolly.data.CloneableSubclass;
import dolly.data.ClassLevelCopyableCloneable;
import dolly.data.PropertyLevelCloneable;
import dolly.data.PropertyLevelCopyableCloneable;

import org.as3commons.reflect.Field;
import org.as3commons.reflect.Type;
import org.flexunit.asserts.assertEquals;
import org.flexunit.asserts.assertNotNull;

use namespace dolly_internal;

public class ClonerTest {

	private var cloneableClass:CloneableClass;
	private var cloneableClassType:Type;

	private var cloneableSubclass:CloneableSubclass;
	private var cloneableSubclassType:Type;

	private var classLevelCopyableCloneable:ClassLevelCopyableCloneable;
	private var classLevelCopyableCloneableType:Type;

	private var propertyLevelCloneable:PropertyLevelCloneable;
	private var propertyLevelCloneableType:Type;

	private var propertyLevelCopyableCloneable:PropertyLevelCopyableCloneable;
	private var propertyLevelCopyableCloneableType:Type;

	[Before]
	public function before():void {
		cloneableClass = new CloneableClass();
		cloneableClass.property1 = "value 1";
		cloneableClass.property2 = "value 2";
		cloneableClass.property3 = "value 3";
		cloneableClass.writableField = "value 4";
		cloneableClassType = Type.forInstance(cloneableClass);

		classLevelCopyableCloneable = new ClassLevelCopyableCloneable();
		classLevelCopyableCloneable.property1 = "value 1";
		classLevelCopyableCloneable.property2 = "value 2";
		classLevelCopyableCloneable.property3 = "value 3";
		classLevelCopyableCloneable.writableField = "value 4";
		classLevelCopyableCloneableType = Type.forInstance(classLevelCopyableCloneable);

		cloneableSubclass = new CloneableSubclass();
		cloneableSubclass.property1 = "value 1";
		cloneableSubclass.property2 = "value 2";
		cloneableSubclass.property3 = "value 3";
		cloneableSubclass.property4 = "value 4";
		cloneableSubclass.property5 = "value 5";
		cloneableSubclass.writableField = "value 6";
		cloneableSubclass.writableField2 = "value 7";
		cloneableSubclassType = Type.forInstance(cloneableSubclass);

		propertyLevelCloneable = new PropertyLevelCloneable();
		propertyLevelCloneable.property1 = "value 1";
		propertyLevelCloneable.property2 = "value 2";
		propertyLevelCloneable.property3 = "value 3";
		propertyLevelCloneable.writableField = "value 4";
		propertyLevelCloneableType = Type.forInstance(propertyLevelCloneable);

		propertyLevelCopyableCloneable = new PropertyLevelCopyableCloneable();
		propertyLevelCopyableCloneable.property1 = "value 1";
		propertyLevelCopyableCloneable.property2 = "value 2";
		propertyLevelCopyableCloneable.property3 = "value 3";
		propertyLevelCopyableCloneable.writableField = "value 4";
		propertyLevelCopyableCloneableType = Type.forInstance(propertyLevelCopyableCloneable);
	}

	[After]
	public function after():void {
		cloneableClass = null;
		cloneableClassType = null;

		classLevelCopyableCloneable = null;
		classLevelCopyableCloneableType = null;

		cloneableSubclass = null;
		cloneableSubclassType = null;

		propertyLevelCloneable = null;
		propertyLevelCloneableType = null;

		propertyLevelCopyableCloneable = null;
		propertyLevelCopyableCloneableType = null;
	}

	[Test]
	public function testFindAllWritableFieldsForTypeClassLevelCloneable():void {
		const cloneableFields:Vector.<Field> = Cloner.findAllWritableFieldsForType(cloneableClassType);
		assertNotNull(cloneableFields);
		assertEquals(4, cloneableFields.length);
	}

	[Test]
	public function testFindAllWritableFieldsForTypeClassLevelCloneableSubclass():void {
		const cloneableFields:Vector.<Field> = Cloner.findAllWritableFieldsForType(cloneableSubclassType);
		assertNotNull(cloneableFields);
		assertEquals(7, cloneableFields.length);
	}

	[Test]
	public function testFindAllWritableFieldsForTypeClassLevelCopyableCloneable():void {
		const cloneableFields:Vector.<Field> = Cloner.findAllWritableFieldsForType(classLevelCopyableCloneableType);
		assertNotNull(cloneableFields);
		assertEquals(4, cloneableFields.length);
	}

	[Test]
	public function testFindAllWritableFieldsForTypePropertyLevelCloneable():void {
		const cloneableFields:Vector.<Field> = Cloner.findAllWritableFieldsForType(propertyLevelCloneableType);
		assertNotNull(cloneableFields);
		assertEquals(3, cloneableFields.length);
	}

	[Test]
	public function testFindAllWritableFieldsForTypePropertyLevelCopyableCloneable():void {
		const cloneableFields:Vector.<Field> = Cloner.findAllWritableFieldsForType(propertyLevelCopyableCloneableType);
		assertNotNull(cloneableFields);
		assertEquals(4, cloneableFields.length);
	}

	[Test]
	public function testCloneClassLevelCloneable():void {
		const clone:CloneableClass = Cloner.clone(cloneableClass);
		assertNotNull(clone);
		assertNotNull(clone.property1);
		assertEquals(clone.property1, cloneableClass.property1);
		assertNotNull(clone.property2);
		assertEquals(clone.property2, cloneableClass.property2);
		assertNotNull(clone.property3);
		assertEquals(clone.property3, cloneableClass.property3);
		assertNotNull(clone.writableField);
		assertEquals(clone.writableField, cloneableClass.writableField);
	}

	[Test]
	public function testCloneClassLevelCloneableSubclass():void {
		const clone:CloneableSubclass = Cloner.clone(cloneableSubclass);
		assertNotNull(clone);
		assertNotNull(clone.property1);
		assertEquals(clone.property1, cloneableSubclass.property1);
		assertNotNull(clone.property2);
		assertEquals(clone.property2, cloneableSubclass.property2);
		assertNotNull(clone.property3);
		assertEquals(clone.property3, cloneableSubclass.property3);
		assertNotNull(clone.property4);
		assertEquals(clone.property4, cloneableSubclass.property4);
		assertNotNull(clone.property5);
		assertEquals(clone.property5, cloneableSubclass.property5);
		assertNotNull(clone.writableField);
		assertEquals(clone.writableField, cloneableSubclass.writableField);
		assertNotNull(clone.writableField2);
		assertEquals(clone.writableField2, cloneableSubclass.writableField2);
	}

	[Test]
	public function testCloneClassLevelCopyableCloneable():void {
		const clone:ClassLevelCopyableCloneable = Cloner.clone(classLevelCopyableCloneable);
		assertNotNull(clone);
		assertNotNull(clone.property1);
		assertEquals(clone.property1, cloneableClass.property1);
		assertNotNull(clone.property2);
		assertEquals(clone.property2, cloneableClass.property2);
		assertNotNull(clone.property3);
		assertEquals(clone.property3, cloneableClass.property3);
		assertNotNull(clone.writableField);
		assertEquals(clone.writableField, cloneableClass.writableField);
	}

	/**
	 * Cloner.clone() method will throw CloningError in this case
	 * because PropertyLevelCloneable class is not cloneable indeed.
	 */
	[Test(expects="dolly.core.errors.CloningError")]
	public function testClonePropertyLevelCloneable():void {
		Cloner.clone(propertyLevelCloneable);
	}

	/**
	 * Cloner.clone() method will throw CloningError in this case
	 * because PropertyLevelCopyableCloneable class is not cloneable indeed.
	 */
	[Test(expects="dolly.core.errors.CloningError")]
	public function testClonePropertyLevelCopyableCloneable():void {
		Cloner.clone(propertyLevelCopyableCloneable);
	}
}
}

package dolly {

import dolly.core.dolly_internal;
import dolly.data.CloneableClass;
import dolly.data.CloneableSubclass;
import dolly.data.ClassLevelCopyableCloneable;
import dolly.data.PropertyLevelCloneable;
import dolly.data.PropertyLevelCopyableCloneable;

import org.as3commons.reflect.Field;
import org.as3commons.reflect.Type;
import org.flexunit.asserts.assertEquals;
import org.flexunit.asserts.assertNotNull;

use namespace dolly_internal;

public class ClonerTest {

	private var cloneableClass:CloneableClass;
	private var cloneableClassType:Type;

	private var cloneableSubclass:CloneableSubclass;
	private var cloneableSubclassType:Type;

	private var classLevelCopyableCloneable:ClassLevelCopyableCloneable;
	private var classLevelCopyableCloneableType:Type;

	private var propertyLevelCloneable:PropertyLevelCloneable;
	private var propertyLevelCloneableType:Type;

	private var propertyLevelCopyableCloneable:PropertyLevelCopyableCloneable;
	private var propertyLevelCopyableCloneableType:Type;

	[Before]
	public function before():void {
		cloneableClass = new CloneableClass();
		cloneableClass.property1 = "value 1";
		cloneableClass.property2 = "value 2";
		cloneableClass.property3 = "value 3";
		cloneableClass.writableField = "value 4";
		cloneableClassType = Type.forInstance(cloneableClass);

		classLevelCopyableCloneable = new ClassLevelCopyableCloneable();
		classLevelCopyableCloneable.property1 = "value 1";
		classLevelCopyableCloneable.property2 = "value 2";
		classLevelCopyableCloneable.property3 = "value 3";
		classLevelCopyableCloneable.writableField = "value 4";
		classLevelCopyableCloneableType = Type.forInstance(classLevelCopyableCloneable);

		cloneableSubclass = new CloneableSubclass();
		cloneableSubclass.property1 = "value 1";
		cloneableSubclass.property2 = "value 2";
		cloneableSubclass.property3 = "value 3";
		cloneableSubclass.property4 = "value 4";
		cloneableSubclass.property5 = "value 5";
		cloneableSubclass.writableField = "value 6";
		cloneableSubclass.writableField2 = "value 7";
		cloneableSubclassType = Type.forInstance(cloneableSubclass);

		propertyLevelCloneable = new PropertyLevelCloneable();
		propertyLevelCloneable.property1 = "value 1";
		propertyLevelCloneable.property2 = "value 2";
		propertyLevelCloneable.property3 = "value 3";
		propertyLevelCloneable.writableField = "value 4";
		propertyLevelCloneableType = Type.forInstance(propertyLevelCloneable);

		propertyLevelCopyableCloneable = new PropertyLevelCopyableCloneable();
		propertyLevelCopyableCloneable.property1 = "value 1";
		propertyLevelCopyableCloneable.property2 = "value 2";
		propertyLevelCopyableCloneable.property3 = "value 3";
		propertyLevelCopyableCloneable.writableField = "value 4";
		propertyLevelCopyableCloneableType = Type.forInstance(propertyLevelCopyableCloneable);
	}

	[After]
	public function after():void {
		cloneableClass = null;
		cloneableClassType = null;

		classLevelCopyableCloneable = null;
		classLevelCopyableCloneableType = null;

		cloneableSubclass = null;
		cloneableSubclassType = null;

		propertyLevelCloneable = null;
		propertyLevelCloneableType = null;

		propertyLevelCopyableCloneable = null;
		propertyLevelCopyableCloneableType = null;
	}

	[Test]
	public function testFindAllWritableFieldsForTypeCloneableClass():void {
		const cloneableFields:Vector.<Field> = Cloner.findAllWritableFieldsForType(cloneableClassType);
		assertNotNull(cloneableFields);
		assertEquals(4, cloneableFields.length);
	}

	[Test]
	public function testFindAllWritableFieldsForTypeCloneableSubclass():void {
		const cloneableFields:Vector.<Field> = Cloner.findAllWritableFieldsForType(cloneableSubclassType);
		assertNotNull(cloneableFields);
		assertEquals(7, cloneableFields.length);
	}

	[Test]
	public function testFindAllWritableFieldsForTypeClassLevelCopyableCloneable():void {
		const cloneableFields:Vector.<Field> = Cloner.findAllWritableFieldsForType(classLevelCopyableCloneableType);
		assertNotNull(cloneableFields);
		assertEquals(4, cloneableFields.length);
	}

	[Test]
	public function testFindAllWritableFieldsForTypePropertyLevelCloneable():void {
		const cloneableFields:Vector.<Field> = Cloner.findAllWritableFieldsForType(propertyLevelCloneableType);
		assertNotNull(cloneableFields);
		assertEquals(3, cloneableFields.length);
	}

	[Test]
	public function testFindAllWritableFieldsForTypePropertyLevelCopyableCloneable():void {
		const cloneableFields:Vector.<Field> = Cloner.findAllWritableFieldsForType(propertyLevelCopyableCloneableType);
		assertNotNull(cloneableFields);
		assertEquals(4, cloneableFields.length);
	}

	[Test]
	public function testCloneClassLevelCloneable():void {
		const clone:CloneableClass = Cloner.clone(cloneableClass);
		assertNotNull(clone);
		assertNotNull(clone.property1);
		assertEquals(clone.property1, cloneableClass.property1);
		assertNotNull(clone.property2);
		assertEquals(clone.property2, cloneableClass.property2);
		assertNotNull(clone.property3);
		assertEquals(clone.property3, cloneableClass.property3);
		assertNotNull(clone.writableField);
		assertEquals(clone.writableField, cloneableClass.writableField);
	}

	[Test]
	public function testCloneClassLevelCloneableSubclass():void {
		const clone:CloneableSubclass = Cloner.clone(cloneableSubclass);
		assertNotNull(clone);
		assertNotNull(clone.property1);
		assertEquals(clone.property1, cloneableSubclass.property1);
		assertNotNull(clone.property2);
		assertEquals(clone.property2, cloneableSubclass.property2);
		assertNotNull(clone.property3);
		assertEquals(clone.property3, cloneableSubclass.property3);
		assertNotNull(clone.property4);
		assertEquals(clone.property4, cloneableSubclass.property4);
		assertNotNull(clone.property5);
		assertEquals(clone.property5, cloneableSubclass.property5);
		assertNotNull(clone.writableField);
		assertEquals(clone.writableField, cloneableSubclass.writableField);
		assertNotNull(clone.writableField2);
		assertEquals(clone.writableField2, cloneableSubclass.writableField2);
	}

	[Test]
	public function testCloneClassLevelCopyableCloneable():void {
		const clone:ClassLevelCopyableCloneable = Cloner.clone(classLevelCopyableCloneable);
		assertNotNull(clone);
		assertNotNull(clone.property1);
		assertEquals(clone.property1, cloneableClass.property1);
		assertNotNull(clone.property2);
		assertEquals(clone.property2, cloneableClass.property2);
		assertNotNull(clone.property3);
		assertEquals(clone.property3, cloneableClass.property3);
		assertNotNull(clone.writableField);
		assertEquals(clone.writableField, cloneableClass.writableField);
	}

	/**
	 * Cloner.clone() method will throw CloningError in this case
	 * because PropertyLevelCloneable class is not cloneable indeed.
	 */
	[Test(expects="dolly.core.errors.CloningError")]
	public function testClonePropertyLevelCloneable():void {
		Cloner.clone(propertyLevelCloneable);
	}

	/**
	 * Cloner.clone() method will throw CloningError in this case
	 * because PropertyLevelCopyableCloneable class is not cloneable indeed.
	 */
	[Test(expects="dolly.core.errors.CloningError")]
	public function testClonePropertyLevelCopyableCloneable():void {
		Cloner.clone(propertyLevelCopyableCloneable);
	}
}
}

Rename methods in tests.

Rename methods in tests.


/*
 * Copyright 2014 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package flash.net {
import flash.events.EventDispatcher;
import flash.utils.ByteArray;
import flash.utils.IDataInput;

public class URLStream extends EventDispatcher implements IDataInput {
  public function URLStream() {
  }
  public native function load(request:URLRequest):void;
  public native function readBytes(bytes:ByteArray, offset:uint = 0, length:uint = 0):void;
  public native function readBoolean():Boolean;
  public native function readByte():int;
  public native function readUnsignedByte():uint;
  public native function readShort():int;
  public native function readUnsignedShort():uint;
  public native function readUnsignedInt():uint;
  public native function readInt():int;
  public native function readFloat():Number;
  public native function readDouble():Number;
  public native function readMultiByte(length:uint, charSet:String):String;
  public native function readUTF():String;
  public native function readUTFBytes(length:uint):String;
  public native function get connected():Boolean;
  public native function get bytesAvailable():uint;
  public native function close():void;
  public native function readObject();
  public native function get objectEncoding():uint;
  public native function set objectEncoding(version:uint):void;
  public native function get endian():String;
  public native function set endian(type:String):void;
  public native function get diskCacheEnabled():Boolean;
  public native function get position():Number;
  public native function set position(offset:Number):void;
  public native function get length():Number;
  public native function stop():void;
}
}

/*
 * Copyright 2014 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package flash.net {
import flash.events.EventDispatcher;
import flash.utils.ByteArray;
import flash.utils.IDataInput;

[native(cls='URLStreamClass')]
public class URLStream extends EventDispatcher implements IDataInput {
  public function URLStream() {
  }
  public native function get connected(): Boolean;
  public native function get bytesAvailable(): uint;
  public native function get objectEncoding(): uint;
  public native function set objectEncoding(version: uint): void;
  public native function get endian(): String;
  public native function set endian(type: String): void;
  public native function get diskCacheEnabled(): Boolean;
  public native function get position(): Number;
  public native function set position(offset: Number): void;
  public native function get length(): Number;
  public native function load(request: URLRequest): void;
  public native function readBytes(bytes: ByteArray, offset: uint = 0, length: uint = 0): void;
  public native function readBoolean(): Boolean;
  public native function readByte(): int;
  public native function readUnsignedByte(): uint;
  public native function readShort(): int;
  public native function readUnsignedShort(): uint;
  public native function readUnsignedInt(): uint;
  public native function readInt(): int;
  public native function readFloat(): Number;
  public native function readDouble(): Number;
  public native function readMultiByte(length: uint, charSet: String): String;
  public native function readUTF(): String;
  public native function readUTFBytes(length: uint): String;
  public native function close(): void;
  public native function readObject();
  public native function stop(): void;
}
}

Add [native] metadata to flash.net.URLStream builtin


import mx.transitions.easing.*;
import com.mosesSupposes.fuse.*;

class idiomesAnimation extends Movieclip
        {

  	private var arrayLang_arr:Array = new Array ("cat", "es", "en", "fr");

			function idiomesAnimation():Void
		{
			this.stop();
			this.onEnterFrame = this.enterSlide;

		}

	private function enterSlide()
                {

			arrayLang_arr[0].slideTo('0', '-40', 0.6, 'easeInOutBack', 1);
			arrayLang_arr[1].slideTo('0', '-40', 0.8, 'easeInOutBack', 1.1);
			arrayLang_arr[2].slideTo('0', '-40', 0.9, 'easeInOutBack', 1.2);
			arrayLang_arr[3].slideTo('0', '-40', 1, 'easeInOutBack', 1.3);

		}

	public function IdiomesColour()
		{

			this.onRelease = this arrayColour;

			target = this.arrayLang_arr[i];
			target._tint = 0x8DC60D;

			return this;

		}

	private function arrayColour()
		{

			for ( var:i:Number=0 ; arrayLang_arr[i] <4; i++)
			{
				this.colorTo("#628D22", 0.3, "easeOutCirc");
				_parent.colorTo('#4b4b4b', 1, 'linear', .2);

			}

		}

	}

import mx.transitions.easing.*;
import com.mosesSupposes.fuse.*;

class com.segonquart.idiomesAnimation extends Movieclip
        {

  	private var arrayLang_arr:Array = new Array ("cat", "es", "en", "fr");

	function idiomesAnimation():Void
		{
			this.stop();
			this.onEnterFrame = this.enterSlide;

		}

	private function enterSlide()
                {

			arrayLang_arr[0].slideTo('0', '-40', 0.6, 'easeInOutBack', 1);
			arrayLang_arr[1].slideTo('0', '-40', 0.8, 'easeInOutBack', 1.1);
			arrayLang_arr[2].slideTo('0', '-40', 0.9, 'easeInOutBack', 1.2);
			arrayLang_arr[3].slideTo('0', '-40', 1, 'easeInOutBack', 1.3);

		}

	public function IdiomesColour()
		{

			this.onRelease = this arrayColour;

			target = this.arrayLang_arr[i];
			target._tint = 0x8DC60D;

			return this;

		}

	private function arrayColour()
		{

			for ( var:i:Number=0 ; arrayLang_arr[i].length <4; i++)
			{
				this.colorTo("#628D22", 0.3, "easeOutCirc");
				_parent.colorTo('#4b4b4b', 1, 'linear', .2);

			}

		}

	}

Update idiomesAnimation.as

Update idiomesAnimation.as


//
// 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);
    }

}

//
// 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 getComponentByName (cclass :String, cname :String) :CharacterComponent
    {
        return _crepo.getComponentByName(cclass, cname);
    }

    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);
    }

}

Add ability to access components by name as well as by ID via the manager.

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


///////////////////////////////////////////////////////////////////////////
// Copyright (c) 2010-2011 Esri. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///////////////////////////////////////////////////////////////////////////
package com.esri.viewer
{

import com.esri.viewer.components.FocusableImage;
import com.esri.viewer.components.TitlebarButton;
import com.esri.viewer.utils.LocalizationUtil;

import flash.events.Event;
import flash.events.MouseEvent;

import mx.controls.Image;
import mx.core.FlexGlobals;
import mx.core.UIComponent;
import mx.events.FlexEvent;
import mx.managers.CursorManager;
import mx.managers.DragManager;

import spark.components.Application;
import spark.components.Group;
import spark.components.SkinnableContainer;

[Event(name="open", type="flash.events.Event")]
[Event(name="minimized", type="flash.events.Event")]
[Event(name="closed", type="flash.events.Event")]
[Event(name="startDrag", type="flash.events.Event")]
[Event(name="stopDrag", type="flash.events.Event")]

[SkinState("open")]
[SkinState("minimized")]
[SkinState("closed")]

public class WidgetTemplate extends SkinnableContainer implements IWidgetTemplate
{
    [SkinPart(required="false")]
    public var widgetFrame:Group;

    [SkinPart(required="false")]
    public var header:Group;

    [SkinPart(required="false")]
    public var headerToolGroup:Group;

    [SkinPart(required="false")]
    public var icon:FocusableImage;

    [SkinPart(required="false")]
    public var closeButton:FocusableImage;

    [SkinPart(required="false")]
    public var minimizeButton:FocusableImage;

    [SkinPart(required="false")]
    public var resizeButton:Image;

    [Bindable]
    public var enableCloseButton:Boolean = true;

    [Bindable]
    public var enableMinimizeButton:Boolean = true;

    [Bindable]
    public var enableDraging:Boolean = true;

    [Bindable]
    public var widgetWidth:Number;

    [Bindable]
    public var widgetHeight:Number;

    [Embed(source="/assets/images/w_resizecursor.png")]
    public var resizeCursor:Class;

    [Embed(source="/assets/images/w_resizecursor_rtl.png")]
    public var resizeCursor_rtl:Class;

    [Bindable]
    public var enableIcon:Boolean = true;

    private static const WIDGET_OPENED:String = "open";

    private static const WIDGET_MINIMIZED:String = "minimized";

    private static const WIDGET_CLOSED:String = "closed";

    private static const WIDGET_START_DRAG:String = "startDrag";

    private static const WIDGET_STOP_DRAG:String = "stopDrag";

    private var _widgetId:Number;

    private var _widgetState:String;

    private var _cursorID:int = 0;

    private var _widgetTitle:String = "";

    private var _widgetIcon:String = "assets/images/i_widget.png";

    [Bindable]
    private var _draggable:Boolean = true;

    private var _resizable:Boolean = true;

    private var _baseWidget:IBaseWidget;

    private var _isPartOfPanel:Boolean;

    [Bindable(event="isPartOfPanelChanged")]
    public function get isPartOfPanel():Boolean
    {
        return _isPartOfPanel;
    }

    public function set baseWidget(value:IBaseWidget):void
    {
        _baseWidget = value;
        _isPartOfPanel = value.isPartOfPanel;
        dispatchEvent(new Event("isPartOfPanelChanged"));

        if (_isPartOfPanel)
        {
            this.enableIcon = this.enableCloseButton = this.enableMinimizeButton = this.enableDraging = false;
        }
        this.resizable = value.isResizeable;
        this.draggable = value.isDraggable;
        this.widgetId = value.widgetId;
        this.widgetTitle = value.widgetTitle;
        this.widgetIcon = value.widgetIcon;
        if (value.initialWidth != 0)
        {
            if (this.minWidth == 0 || isNaN(this.minWidth) || value.initialWidth > this.minWidth)
            {
                this.width = value.initialWidth;
                this.widgetWidth = value.initialWidth;
            }
        }
        if (value.initialHeight != 0)
        {
            if (this.minHeight == 0 || isNaN(this.minHeight) || value.initialHeight > this.minHeight)
            {
                this.height = value.initialHeight;
                this.widgetHeight = value.initialHeight;
            }
        }
    }

    public function get baseWidget():IBaseWidget
    {
        return _baseWidget;
    }

    public function set resizable(value:Boolean):void
    {
        _resizable = value;
        resizeButton.visible = _resizable;
    }

    [Bindable]
    public function get resizable():Boolean
    {
        return _resizable;
    }

    public function set draggable(value:Boolean):void
    {
        if (enableDraging)
        {
            _draggable = value;
        }
        else
        {
            _draggable = false;
        }
    }

    public function get widgetId():Number
    {
        return _widgetId;
    }

    public function set widgetId(value:Number):void
    {
        _widgetId = value;
    }

    [Bindable]
    public function get widgetTitle():String
    {
        return _widgetTitle;
    }

    public function set widgetTitle(value:String):void
    {
        _widgetTitle = value;
    }

    [Bindable]
    public function get widgetIcon():String
    {
        return _widgetIcon;
    }

    public function set widgetIcon(value:String):void
    {
        _widgetIcon = value;
    }

    public function set widgetState(value:String):void
    {
        this.widgetFrame.toolTip = "";
        this.icon.toolTip = "";
        _widgetState = value;
        if (_widgetState == WIDGET_MINIMIZED)
        {
            this.widgetFrame.toolTip = this.widgetTitle;
            this.icon.toolTip = this.widgetTitle;
        }
        invalidateSkinState();

        dispatchEvent(new Event(value));
    }

    public function get widgetState():String
    {
        return _widgetState;
    }

    private var _selectedTitlebarButtonIndex:int = -1;

    private var _selectedTitlebarButtonIndexChanged:Boolean = false;

    public function get selectedTitlebarButtonIndex():int
    {
        return _selectedTitlebarButtonIndex;
    }

    public function set selectedTitlebarButtonIndex(value:int):void
    {
        if (_selectedTitlebarButtonIndex != value)
        {
            _selectedTitlebarButtonIndex = value;
            _selectedTitlebarButtonIndexChanged = true;
            invalidateProperties();
        }
    }

    public function WidgetTemplate()
    {
        super();

        this.width = 300;
        this.height = 300;

        this.hasFocusableChildren = true;

        this.addEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHandler);
    }

    private function creationCompleteHandler(event:Event):void
    {
        widgetWidth = width;
        widgetHeight = height;

        this.closeButton.toolTip = LocalizationUtil.getDefaultString("close");
        this.minimizeButton.toolTip = LocalizationUtil.getDefaultString("minimize");
    }

    protected override function partAdded(partName:String, instance:Object):void
    {
        super.partAdded(partName, instance);
        if (instance == icon)
        {
            icon.addEventListener(MouseEvent.CLICK, icon_clickHandler);
        }
        if (instance == widgetFrame)
        {
            widgetFrame.addEventListener(MouseEvent.MOUSE_DOWN, mouse_downHandler);
            widgetFrame.addEventListener(MouseEvent.MOUSE_UP, mouse_upHandler);

            widgetFrame.stage.addEventListener(MouseEvent.MOUSE_UP, mouse_upHandler);
            widgetFrame.stage.addEventListener(Event.MOUSE_LEAVE, stageout_Handler);
        }
        if (instance == header)
        {
            header.addEventListener(MouseEvent.MOUSE_DOWN, mouse_downHandler);
            header.addEventListener(MouseEvent.MOUSE_UP, mouse_upHandler);
        }
        if (instance == closeButton)
        {
            closeButton.addEventListener(MouseEvent.CLICK, close_clickHandler);
        }
        if (instance == minimizeButton)
        {
            minimizeButton.addEventListener(MouseEvent.CLICK, minimize_clickHandler);
        }
        if (instance == resizeButton)
        {
            resizeButton.addEventListener(MouseEvent.MOUSE_OVER, resize_overHandler);
            resizeButton.addEventListener(MouseEvent.MOUSE_OUT, resize_outHandler);
            resizeButton.addEventListener(MouseEvent.MOUSE_DOWN, resize_downHandler);
        }
    }

    override protected function getCurrentSkinState():String
    {
        return _widgetState;
    }

    override protected function commitProperties():void
    {
        super.commitProperties();

        if (_selectedTitlebarButtonIndexChanged)
        {
            _selectedTitlebarButtonIndexChanged = false;
            for (var i:int = 0, n:int = headerToolGroup.numElements; i < n; i++)
            {
                var btn:TitlebarButton = TitlebarButton(headerToolGroup.getElementAt(i));
                if (i == _selectedTitlebarButtonIndex)
                {
                    btn.selected = true;
                }
                else
                {
                    btn.selected = false;
                }
            }
        }
    }

    public function mouse_downHandler(event:MouseEvent):void
    {
        if (_draggable && enableDraging)
        {
            header.addEventListener(MouseEvent.MOUSE_MOVE, mouse_moveHandler);
            widgetFrame.addEventListener(MouseEvent.MOUSE_MOVE, mouse_moveHandler);
        }
    }

    private var widgetMoveStarted:Boolean = false;
    private var xResizeStart:Number;
    private var yResizeStart:Number;

    private function mouse_moveHandler(event:MouseEvent):void
    {
        if (!widgetMoveStarted)
        {
            widgetMoveStarted = true;

            //TODO: not for V2.0
            //AppEvent.dispatch(AppEvent.CHANGE_LAYOUT, LAYOUT_BASIC));
            if (_widgetState != WIDGET_MINIMIZED)
            {
                this.alpha = 0.7;
            }
            var widget:UIComponent = parent as UIComponent;

            if (!DragManager.isDragging)
            {
                widget.startDrag();
                dispatchEvent(new Event(WIDGET_START_DRAG));
            }

            if (_resizable)
            {
                AppEvent.dispatch(AppEvent.WIDGET_FOCUS, widgetId);
            }
        }
    }

    private function mouse_upHandler(event:MouseEvent):void
    {
        header.removeEventListener(MouseEvent.MOUSE_MOVE, mouse_moveHandler);
        widgetFrame.removeEventListener(MouseEvent.MOUSE_MOVE, mouse_moveHandler);

        if (_widgetState != WIDGET_MINIMIZED)
        {
            this.alpha = 1;
        }
        var widget:UIComponent = parent as UIComponent;

        widget.stopDrag();
        dispatchEvent(new Event(WIDGET_STOP_DRAG));

        var appHeight:Number = FlexGlobals.topLevelApplication.height;
        var appWidth:Number = FlexGlobals.topLevelApplication.width;

        if (widget.y < 0)
        {
            widget.y = 0;
        }
        if (widget.y > (appHeight - 40))
        {
            widget.y = appHeight - 40;
        }
        if (widget.x < 0)
        {
            widget.x = 20;
        }

        if (widget.x > (appWidth - 40))
        {
            widget.x = appWidth - 40;
        }

        // clear constraints since x and y have been set
        widget.left = widget.right = widget.top = widget.bottom = undefined;

        widgetMoveStarted = false;
    }

    private function stageout_Handler(event:Event):void
    {
        if (widgetMoveStarted)
        {
            mouse_upHandler(null);
        }
    }

    protected function icon_clickHandler(event:MouseEvent):void
    {
        if (_baseWidget)
        {
            _baseWidget.setState(WIDGET_OPENED);
        }

        this.widgetFrame.toolTip = "";
        this.icon.toolTip = "";
    }

    protected function close_clickHandler(event:MouseEvent):void
    {
        if (_baseWidget)
        {
            _baseWidget.setState(WIDGET_CLOSED);
        }
    }

    protected function minimize_clickHandler(event:MouseEvent):void
    {
        if (_baseWidget)
        {
            _baseWidget.setState(WIDGET_MINIMIZED);
        }

        this.widgetFrame.toolTip = this.widgetTitle;
        this.icon.toolTip = this.widgetTitle;
    }

    private function resize_overHandler(event:MouseEvent):void
    {
        if (isRtl())
        {
            _cursorID = CursorManager.setCursor(resizeCursor_rtl, 2, -10, -10);
        }
        else
        {
            _cursorID = CursorManager.setCursor(resizeCursor, 2, -10, -10);
        }
    }

    private function resize_outHandler(event:MouseEvent):void
    {
        CursorManager.removeCursor(_cursorID);
    }

    private function resize_downHandler(event:MouseEvent):void
    {
        if (_resizable)
        {
            xResizeStart = event.stageX
            yResizeStart = event.stageY;

            /*TODO: for now, it can't be resized when is not basic layout*/
            stage.addEventListener(MouseEvent.MOUSE_MOVE, resize_moveHandler);
            stage.addEventListener(MouseEvent.MOUSE_UP, resize_upHandler);
        }
    }

    public function isRtl():Boolean
    {
        var result:Boolean = false;
        try
        {
            result = (FlexGlobals.topLevelApplication as Application).layoutDirection == "rtl";
        }
        catch (error:Error)
        {
            result = false;
        }
        return result;
    }

    private function resize_moveHandler(event:MouseEvent):void
    {
        // clear constraints
        var widget:UIComponent = parent as UIComponent;
        widget.left = widget.right = widget.top = widget.bottom = undefined;

        var xResizeEnd:Number = event.stageX;
        var yResizeEnd:Number = event.stageY;

        var isWithinVerticalBoundaries:Boolean = (stage.mouseY < stage.height - 20);
        var isWithinHorizontalBoundaries:Boolean = isRtl() ?
            stage.mouseX > 20 : stage.mouseX < stage.width - 20;

        if (isWithinHorizontalBoundaries && isWithinVerticalBoundaries)
        {
            // if there is minWidth and minHeight specified on the container, use them while resizing
            const minimumResizeWidth:Number = minWidth ? minWidth : 200;
            const minimumResizeHeight:Number = minHeight ? minHeight : 100;

            var deltaX:Number = xResizeEnd - xResizeStart;
            var deltaY:Number = yResizeEnd - yResizeStart;

            var calculatedWidth:Number = isRtl() ? widgetWidth - deltaX : widgetWidth + deltaX;
            var calculatedHeight:Number = widgetHeight + deltaY;

            if (calculatedWidth > minimumResizeWidth)
            {
                width = calculatedWidth;
            }
            if (calculatedHeight > minimumResizeHeight)
            {
                height = calculatedHeight;
            }
        }
    }

    private function resize_upHandler(event:MouseEvent):void
    {
        widgetWidth = width;
        widgetHeight = height;

        stage.removeEventListener(MouseEvent.MOUSE_MOVE, resize_moveHandler);
        stage.removeEventListener(MouseEvent.MOUSE_UP, resize_upHandler);

        var p:UIComponent = parent as UIComponent;
        p.stopDrag();
    }

    /**
     * Adds a new titlebar button - which usually represent a "state" or "view" within the widget.
     * For example, the Search widget has three titlebar buttons: one for "Select features" (interactively),
     * one for "Select by attribute", and one for "Results".
     * Each button corresponds to a function
     *
     * @param btnIcon URL to icon to use for this button.
     * @param btnTip Tooltip for this button.
     * @param btnFunction The function to call when this button is clicked.
     * @param selectable Boolean.
     */
    public function addTitlebarButton(btnIcon:String, btnTip:String, btnFunction:Function, selectable:Boolean = true):void
    {
        var btn:TitlebarButton = new TitlebarButton();
        btn.callback = btnFunction;
        btn.selectable = selectable;
        btn.source = btnIcon;
        btn.toolTip = btnTip;

        if (selectable)
        {
            btn.addEventListener(MouseEvent.CLICK, titlebarButton_clickHandler);
            if (headerToolGroup.numElements == 0)
            {
                selectedTitlebarButtonIndex = 0; // automatically select the first button added
            }
        }

        headerToolGroup.addElement(btn);
    }

    private function titlebarButton_clickHandler(event:MouseEvent):void
    {
        selectedTitlebarButtonIndex = headerToolGroup.getElementIndex(TitlebarButton(event.currentTarget));
    }
}

}

Clean up.

Clean up.


package {
	import flash.utils.ByteArray;
	import flash.display.Sprite;
	import flash.media.Microphone;
	import flash.media.SoundMixer;
	import flash.media.SoundTransform;
	import flash.system.Security;
	import flash.system.SecurityPanel;
	import org.bytearray.micrecorder.*;
	import org.bytearray.micrecorder.events.RecordingEvent;
	import org.bytearray.micrecorder.encoder.WaveEncoder;
	import flash.events.Event;
	import flash.events.ActivityEvent;
	import flash.net.FileReference;
	import flash.external.ExternalInterface;
	import flash.events.StatusEvent;
    import flash.media.Microphone;

	import Base64;

	public class Recorder extends Sprite {

		private var muted:Boolean = true;
		private var recording:Boolean = false;
		private var mic:Microphone;
		private var wavEncoder:WaveEncoder = new WaveEncoder();
		private var micRecorder:MicRecorder = new MicRecorder(wavEncoder);
		private var fileReference:FileReference = new FileReference();

		public function Recorder() {
			initializeMicRecorder();
			addEventListeners();
			Security.showSettings("2");
		}

		// Methods
		public function isMuted():Boolean {
			return muted;
		}

		public function getActivityLevel():Number {
			return mic.activityLevel;
		}

		public function getDataURL():String {
			return 'data:audio/wav;base64,' + Base64.encode(micRecorder.output);
		}

		public function startRecording():void {
			if (!recording) {
				recording = true;
				micRecorder.record();
			}
		}

		public function stopRecording():void {
			if (recording) {
				recording = false;
				micRecorder.stop();
				mic.setLoopBack(false);
			}
		}

		// Event Handlers
		private function onRecording(e:RecordingEvent):void {
			dispatchEvent(new Event('Recorder.recording', true));
		}

		private function onComplete(e:Event):void {
			dispatchEvent(new Event('Recorder.complete', true));
		}

		private function onMicStatus(e:StatusEvent):void {
			if (e.code == "Microphone.Unmuted"){
				muted = false;
				mic.removeEventListener(StatusEvent.STATUS, onMicStatus);
				dispatchEvent(new Event('Recorder.enabled', true));
			} else if (e.code == "Microphone.Muted") {
				muted = true;
				mic.removeEventListener(StatusEvent.STATUS, onMicStatus);
				dispatchEvent(new Event('Recorder.disabled', true));
			}
		}

		// Just Getting things out of the way
		private function muteSpeakers():void {
			var transform1:SoundTransform=new SoundTransform();
			transform1.volume=0; // goes from 0 to 1
			flash.media.SoundMixer.soundTransform=transform1;
		}

		private function initializeMicRecorder():void {
			muteSpeakers();
			mic = Microphone.getMicrophone();
			mic.setSilenceLevel(0);
			mic.gain = 100;
			mic.setLoopBack(true);
			mic.setUseEchoSuppression(true);
		}

		private function addEventListeners():void {
			mic.addEventListener(StatusEvent.STATUS, onMicStatus, false, 0, true);
			micRecorder.addEventListener(RecordingEvent.RECORDING, onRecording);
			micRecorder.addEventListener(Event.COMPLETE, onComplete);
		}

	}

}

package {
	import flash.utils.ByteArray;
	import flash.display.Sprite;
	import flash.media.Microphone;
	import flash.media.SoundMixer;
	import flash.media.SoundTransform;
	import flash.system.Security;
	import flash.system.SecurityPanel;
	import org.bytearray.micrecorder.*;
	import org.bytearray.micrecorder.events.RecordingEvent;
	import org.bytearray.micrecorder.encoder.WaveEncoder;
	import flash.events.Event;
	import flash.events.ActivityEvent;
	import flash.net.FileReference;
	import flash.external.ExternalInterface;
	import flash.events.StatusEvent;
    import flash.media.Microphone;

	import Base64;
	import RecorderEvent;

	public class Recorder extends Sprite {

		private var muted:Boolean = true;
		private var recording:Boolean = false;
		private var time:int = 0;
		private var duration:int = 0;

		private var mic:Microphone;
		private var wavEncoder:WaveEncoder = new WaveEncoder();
		private var micRecorder:MicRecorder = new MicRecorder(wavEncoder);
		private var fileReference:FileReference = new FileReference();

		public function Recorder() {
			initializeMicRecorder();
			addEventListeners();
			Security.showSettings("2");
		}

		private function addEventListeners():void {
			addEventListener(Event.ENTER_FRAME, onEnterFrame);
			mic.addEventListener(StatusEvent.STATUS, onMicStatus, false, 0, true);
			micRecorder.addEventListener(RecordingEvent.RECORDING, onRecording);
			micRecorder.addEventListener(Event.COMPLETE, onComplete);
		}

		// Methods
		public function isMuted():Boolean {
			return muted;
		}

		public function getActivityLevel():int {
			return mic.activityLevel;
		}

		public function getTime():int {
			return this.time;
		}

		public function getDuration():int {
			return this.duration;
		}

		public function getDataURL():String {
			return 'data:audio/wav;base64,' + Base64.encode(micRecorder.output);
		}

		public function startRecording():void {
			if (!recording) {
				recording = true;
				micRecorder.record();
			}
		}

		public function stopRecording():void {
			if (recording) {
				recording = false;
				micRecorder.stop();
				mic.setLoopBack(false);
			}
		}

		// Event Handlers
		private function onEnterFrame(e:Event):void {
			var data:Object = {muted: this.muted, recording: this.recording, volume: mic.activityLevel};
			if (this.time) data.time = this.time;
			dispatchEvent(new RecorderEvent(RecorderEvent.STATUS, data, true));
		}

		private function onRecording(e:RecordingEvent):void {
			var data:Object = {time: e.time, volume: mic.activityLevel};
			dispatchEvent(new RecorderEvent(RecorderEvent.RECORDING, data, true));
		}

		private function onComplete(e:Event):void {
			var data:Object = {};
			dispatchEvent(new RecorderEvent(RecorderEvent.COMPLETE, data, true));
		}

		private function onMicStatus(e:StatusEvent):void {
			if (e.code == "Microphone.Unmuted"){
				muted = false;
				mic.removeEventListener(StatusEvent.STATUS, onMicStatus);
				dispatchEvent(new RecorderEvent(RecorderEvent.ENABLED, true));
			} else if (e.code == "Microphone.Muted") {
				mic.removeEventListener(StatusEvent.STATUS, onMicStatus);
				dispatchEvent(new RecorderEvent(RecorderEvent.DISABLED, true));
			}
		}

		// Just Getting things out of the way
		private function muteSpeakers():void {
			var transform1:SoundTransform=new SoundTransform();
			transform1.volume=0; // goes from 0 to 1
			flash.media.SoundMixer.soundTransform=transform1;
		}

		private function initializeMicRecorder():void {
			muteSpeakers();
			mic = Microphone.getMicrophone();
			mic.setSilenceLevel(0);
			mic.gain = 100;
			mic.setLoopBack(true);
			mic.setUseEchoSuppression(true);
		}

	}

}

Update Recorder to dispatch only RecorderEvents


/**
  * LzKeyboardKernel.lzs
  *
  * @copyright Copyright 2001-2008 Laszlo Systems, Inc.  All Rights Reserved.
  *            Use is subject to license terms.
  *
  * @topic Kernel
  * @subtopic AS2
  */

// Receives keyboard events from the runtime
class LzKeyboardKernelClass
{
    function __keyboardEvent ( e, t ){
        var delta = {};
        var s, k = e.keyCode;
        s = String.fromCharCode(k).toLowerCase();
        delta[s] = (t == "onkeydown");
        if (this.__callback) this.__scope[this.__callback](delta, k, t);
    }

    var __callback = null;
    var __scope = null;

    function setCallback (scope, funcname) {
        this.__scope = scope;
        this.__callback = funcname;
    }
    // Called by lz.Keys when the last focusable element was reached.
    function gotLastFocus() {
    }
} // End of LzKeyboardKernelClass

var LzKeyboardKernel = new LzKeyboardKernelClass ();

/**
  * LzKeyboardKernel.lzs
  *
  * @copyright Copyright 2001-2008 Laszlo Systems, Inc.  All Rights Reserved.
  *            Use is subject to license terms.
  *
  * @topic Kernel
  * @subtopic AS2
  */

// Receives keyboard events from the runtime
class LzKeyboardKernelClass
{
    function __keyboardEvent ( e, t ){
        var delta = {};
        var s, k = e.keyCode;
        var keyisdown = t == 'onkeydown';
        s = String.fromCharCode(k).toLowerCase();
        if (keyisdown) {
            // prevent duplicate onkeydown events - see LPP-7432
            if (k == __lastkeydown) return;
            __lastkeydown = k;
        } else {
            __lastkeydown = null;
        }
        delta[s] = keyisdown;
        if (this.__callback) this.__scope[this.__callback](delta, k, t);
    }

    var __callback = null;
    var __scope = null;
    var __lastkeydown = null;

    function setCallback (scope, funcname) {
        this.__scope = scope;
        this.__callback = funcname;
    }
    // Called by lz.Keys when the last focusable element was reached.
    function gotLastFocus() {
    }
} // End of LzKeyboardKernelClass

var LzKeyboardKernel = new LzKeyboardKernelClass ();

Change 20081209-maxcarlson-K by maxcarlson@Bank.lan on 2008-12-09 05:03:02 PST
    in /Users/maxcarlson/openlaszlo/trunk-clean
    for http://svn.openlaszlo.org/openlaszlo/trunk

Summary: swf9: prevent duplicate onkeydown events

Bugs Fixed: LPP-7432 - onkeydown event keep firing

Technical Reviewer: andre.bargull@udo.edu
QA Reviewer: promanik

Details: Cache last value of onkeydown to prevent duplicate events from being sent

Tests: See LPP-7432

git-svn-id: d62bde4b5aa582fdf07c8d403e53e0399a7ed285@12035 fa20e4f9-1d0a-0410-b5f3-dc9c16b8b17c


/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 package org.mangui.osmf.plugins.traits {
    import org.mangui.hls.HLS;
    import org.mangui.hls.event.HLSEvent;
    import org.osmf.traits.DynamicStreamTrait;
    import org.osmf.utils.OSMFStrings;

    CONFIG::LOGGING {
    import org.mangui.hls.utils.Log;
    }

    public class HLSDynamicStreamTrait extends DynamicStreamTrait {
        private var _hls : HLS;

        public function HLSDynamicStreamTrait(hls : HLS) {
            CONFIG::LOGGING {
            Log.debug("HLSDynamicStreamTrait()");
            }
            _hls = hls;
            _hls.addEventListener(HLSEvent.LEVEL_SWITCH, _levelSwitchHandler);
            super(true, _hls.startLevel, hls.levels.length);
        }

        override public function dispose() : void {
            CONFIG::LOGGING {
            Log.debug("HLSDynamicStreamTrait:dispose");
            }
            _hls.removeEventListener(HLSEvent.LEVEL_SWITCH, _levelSwitchHandler);
            super.dispose();
        }

        override public function getBitrateForIndex(index : int) : Number {
            if (index > numDynamicStreams - 1 || index < 0) {
                throw new RangeError(OSMFStrings.getString(OSMFStrings.STREAMSWITCH_INVALID_INDEX));
            }
            var bitrate : Number = _hls.levels[index].bitrate / 1000;
            CONFIG::LOGGING {
            Log.debug("HLSDynamicStreamTrait:getBitrateForIndex(" + index + ")=" + bitrate);
            }
            return bitrate;
        }

        override public function switchTo(index : int) : void {
            CONFIG::LOGGING {
            Log.debug("HLSDynamicStreamTrait:switchTo(" + index + ")/max:" + maxAllowedIndex);
            }
            if (index < 0 || index > maxAllowedIndex) {
                throw new RangeError(OSMFStrings.getString(OSMFStrings.STREAMSWITCH_INVALID_INDEX));
            }
            autoSwitch = false;
            if (!switching) {
                setSwitching(true, index);
            }
        }

        override protected function autoSwitchChangeStart(value : Boolean) : void {
            CONFIG::LOGGING {
            Log.debug("HLSDynamicStreamTrait:autoSwitchChangeStart:" + value);
            }
            if (value == true && _hls.autoLevel == false) {
                _hls.loadLevel = -1;
                // only seek if position is set
                if (!isNaN(_hls.position)) {
                    _hls.stream.seek(_hls.position);
                }
            }
        }

        override protected function switchingChangeStart(newSwitching : Boolean, index : int) : void {
            CONFIG::LOGGING {
            Log.debug("HLSDynamicStreamTrait:switchingChangeStart(newSwitching/index):" + newSwitching + "/" + index);
            }
            if (newSwitching) {
                _hls.loadLevel = index;
            }
        }

        /** Update playback position/duration **/
        private function _levelSwitchHandler(event : HLSEvent) : void {
            var newLevel : int = event.level;
            CONFIG::LOGGING {
            Log.debug("HLSDynamicStreamTrait:_qualitySwitchHandler:" + newLevel);
            }
            setCurrentIndex(newLevel);
            setSwitching(false, newLevel);
        };
    }
}

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 package org.mangui.osmf.plugins.traits {
    import org.mangui.hls.HLS;
    import org.mangui.hls.event.HLSEvent;
    import org.osmf.traits.DynamicStreamTrait;
    import org.osmf.utils.OSMFStrings;

    CONFIG::LOGGING {
    import org.mangui.hls.utils.Log;
    }

    public class HLSDynamicStreamTrait extends DynamicStreamTrait {
        private var _hls : HLS;

        public function HLSDynamicStreamTrait(hls : HLS) {
            CONFIG::LOGGING {
            Log.debug("HLSDynamicStreamTrait()");
            }
            _hls = hls;
            _hls.addEventListener(HLSEvent.LEVEL_SWITCH, _levelSwitchHandler);
            super(true, _hls.startLevel, hls.levels.length);
        }

        override public function dispose() : void {
            CONFIG::LOGGING {
            Log.debug("HLSDynamicStreamTrait:dispose");
            }
            _hls.removeEventListener(HLSEvent.LEVEL_SWITCH, _levelSwitchHandler);
            super.dispose();
        }

        override public function getBitrateForIndex(index : int) : Number {
            if (index > numDynamicStreams - 1 || index < 0) {
                throw new RangeError(OSMFStrings.getString(OSMFStrings.STREAMSWITCH_INVALID_INDEX));
            }
            var bitrate : Number = _hls.levels[index].bitrate / 1000;
            CONFIG::LOGGING {
            Log.debug("HLSDynamicStreamTrait:getBitrateForIndex(" + index + ")=" + bitrate);
            }
            return bitrate;
        }

        override public function switchTo(index : int) : void {
            CONFIG::LOGGING {
            Log.debug("HLSDynamicStreamTrait:switchTo(" + index + ")/max:" + maxAllowedIndex);
            }
            if (index < 0 || index > maxAllowedIndex) {
                throw new RangeError(OSMFStrings.getString(OSMFStrings.STREAMSWITCH_INVALID_INDEX));
            }
            autoSwitch = false;
            if (!switching) {
                setSwitching(true, index);
            }
        }

        override protected function autoSwitchChangeStart(value : Boolean) : void {
            CONFIG::LOGGING {
            Log.debug("HLSDynamicStreamTrait:autoSwitchChangeStart:" + value);
            }
            if (value == true && _hls.autoLevel == false) {
                _hls.nextLevel = -1;
            }
        }

        override protected function switchingChangeStart(newSwitching : Boolean, index : int) : void {
            CONFIG::LOGGING {
            Log.debug("HLSDynamicStreamTrait:switchingChangeStart(newSwitching/index):" + newSwitching + "/" + index);
            }
            if (newSwitching) {
                _hls.currentLevel = index;
            }
        }

        /** Update playback position/duration **/
        private function _levelSwitchHandler(event : HLSEvent) : void {
            var newLevel : int = event.level;
            CONFIG::LOGGING {
            Log.debug("HLSDynamicStreamTrait:_qualitySwitchHandler:" + newLevel);
            }
            setCurrentIndex(newLevel);
            setSwitching(false, newLevel);
        };
    }
}

speed up level switching

flashlsOSMF: speed up level switching


/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mangui.osmf.plugins.utils {
    import org.mangui.hls.event.HLSError;
    import org.mangui.hls.event.HLSEvent;
    import org.osmf.events.MediaErrorCodes;

    public class ErrorManager {

        public static function getMediaErrorCode(event : HLSEvent) : int {
            var errorCode : int = MediaErrorCodes.NETSTREAM_PLAY_FAILED;
            if (event && event.error) {
                switch (event.error.code) {
                    case HLSError.FRAGMENT_LOADING_ERROR:
                    case HLSError.FRAGMENT_LOADING_CROSSDOMAIN_ERROR:
                    case HLSError.KEY_LOADING_ERROR:
                    case HLSError.KEY_LOADING_CROSSDOMAIN_ERROR:
                    case HLSError.MANIFEST_LOADING_CROSSDOMAIN_ERROR:
                    case HLSError.MANIFEST_LOADING_IO_ERROR:
                        errorCode = MediaErrorCodes.IO_ERROR;
                        break;
                    case org.mangui.hls.event.HLSError.FRAGMENT_PARSING_ERROR:
                    case org.mangui.hls.event.HLSError.KEY_PARSING_ERROR:
                    case org.mangui.hls.event.HLSError.MANIFEST_PARSING_ERROR:
                        errorCode = MediaErrorCodes.NETSTREAM_FILE_STRUCTURE_INVALID;
                        break;
                    case org.mangui.hls.event.HLSError.TAG_APPENDING_ERROR:
                        errorCode = MediaErrorCodes.ARGUMENT_ERROR;
                        break;
                }
            }
            return errorCode;
        };

        public static function getMediaErrorMessage(event : HLSEvent) : String {
            return (event && event.error) ? event.error.msg : "Unknown error";
        };
    };
}

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mangui.osmf.plugins.utils {
    import org.mangui.hls.event.HLSError;
    import org.mangui.hls.event.HLSEvent;
    import org.osmf.events.MediaErrorCodes;

    public class ErrorManager {

        public static function getMediaErrorCode(event : HLSEvent) : int {
            var errorCode : int = MediaErrorCodes.NETSTREAM_PLAY_FAILED;
            if (event && event.error) {
                switch (event.error.code) {
                    case HLSError.FRAGMENT_LOADING_ERROR:
                    case HLSError.KEY_LOADING_ERROR:
                    case HLSError.MANIFEST_LOADING_IO_ERROR:
                        errorCode = MediaErrorCodes.IO_ERROR;
                        break;
                    case HLSError.FRAGMENT_LOADING_CROSSDOMAIN_ERROR:
                    case HLSError.KEY_LOADING_CROSSDOMAIN_ERROR:
                    case HLSError.MANIFEST_LOADING_CROSSDOMAIN_ERROR:
                        errorCode = MediaErrorCodes.SECURITY_ERROR
                        break;
                    case org.mangui.hls.event.HLSError.FRAGMENT_PARSING_ERROR:
                    case org.mangui.hls.event.HLSError.KEY_PARSING_ERROR:
                    case org.mangui.hls.event.HLSError.MANIFEST_PARSING_ERROR:
                        errorCode = MediaErrorCodes.NETSTREAM_FILE_STRUCTURE_INVALID;
                        break;
                    case org.mangui.hls.event.HLSError.TAG_APPENDING_ERROR:
                        errorCode = MediaErrorCodes.ARGUMENT_ERROR;
                        break;
                }
            }
            return errorCode;
        };

        public static function getMediaErrorMessage(event : HLSEvent) : String {
            return (event && event.error) ? event.error.msg : "Unknown error";
        };
    };
}

Fix mapping of HLSError.FRAGMENT_LOADING_CROSSDOMAIN_ERROR, HLSError.KEY_LOADING_CROSSDOMAIN_ERROR, HLSError.MANIFEST_LOADING_CROSSDOMAIN_ERROR to MediaErrorCodes.SECURITY_ERROR instead of MediaErrorCodes.IO_ERROR