//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// 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.util {

public class RingBuffer
{
    /** Creates a new RingBuffer with the specified capacity. */
    public function RingBuffer (capacity :uint = 1)
    {
        _capacity = capacity;
        _array.length = _capacity;
    }

    /** Returns the capacity of the RingBuffer. */
    public function get capacity () :uint
    {
        return _capacity;
    }

    /**
     * Sets the capacity of the RingBuffer.
     * If the new capacity is less than the RingBuffer's length,
     * elements will be removed from the end of the RingBuffer
     * to accommodate the smaller capacity.
     */
    public function set capacity (newCapacity :uint) :void
    {
        // Copy all the elements to a new array.
        var newArray :Array = new Array();
        var newLength :uint = Math.min(_length, newCapacity);
        newArray.length = newCapacity;
        for (var i :uint = 0; i < newLength; ++i) {
            newArray[i] = this.at(i);
        }

        _capacity = newCapacity;
        _length = newLength;
        _array = newArray;
        _firstIndex = 0;
    }

    /** Returns the number of elements currently stored in the RingBuffer. */
    public function get length () :uint
    {
        return _length;
    }

    /** Returns true if the RingBuffer contains 0 elements. */
    public function get empty () :Boolean
    {
        return (0 == _length);
    }

    /**
     * Adds the specified elements to the front of the RingBuffer.
     * If the RingBuffer's length is equal to its capacity, this
     * will cause elements to be removed from the back of
     * the RingBuffer.
     * Returns the new length of the RingBuffer.
     */
    public function unshift (...args) :uint
    {
        for (var i :int = args.length - 1; i >= 0; --i) {
            var index :uint = (_firstIndex > 0 ? _firstIndex - 1 : _capacity - 1);
            _array[index] = args[i];
            _length = Math.min(_length + 1, _capacity);
            _firstIndex = index;
        }

        return _length;
    }

    /**
     * Adds the specified elements to the back of the RingBuffer.
     * If the RingBuffer's length is equal to its capacity, this
     * will cause a elements to be removed from the front of
     * the RingBuffer.
     * Returns the new length of the RingBuffer.
     */
    public function push (...args) :uint
    {
        for (var i :uint = 0; i < args.length; ++i) {
            var index :uint = ((_firstIndex + _length) % _capacity);
            _array[index] = args[i];
            _length = Math.min(_length + 1, _capacity);

            // did we overwrite the first index?
            if (index == _firstIndex && _length == _capacity) {
                _firstIndex = (_firstIndex < _capacity - 1 ? _firstIndex + 1 : 0);
            }
        }

        return _length;
    }

    /**
     * Removes the first element from the RingBuffer and returns it.
     * If the RingBuffer is empty, shift() will return undefined.
     */
    public function shift () :*
    {
        if (this.empty) {
            return undefined;
        }

        var obj :* = _array[_firstIndex];
        _array[_firstIndex] = undefined;
        _firstIndex = (_firstIndex < _capacity - 1 ? _firstIndex + 1 : 0);
        --_length;

        return obj;
    }

    /**
     * Removes the last element from the RingBuffer and returns it.
     * If the RingBuffer is empty, pop() will return undefined.
     */
    public function pop () :*
    {
        if (this.empty) {
            return undefined;
        }

        var lastIndex :uint = ((_firstIndex + _length - 1) % _capacity);

        var obj :* = _array[lastIndex];
        _array[lastIndex] = undefined;
        --_length;

        return obj;
    }

    /** Removes all elements from the RingBuffer. */
    public function clear () :void
    {
        _array = new Array();
        _array.length = _capacity;
        _length = 0;
        _firstIndex = 0;
    }

    /**
     * Returns the element at the specified index.
     * If index >= length, at() will return undefined.
     */
    public function at (index :uint) :*
    {
        if (index >= _length) {
            return undefined;
        } else {
            var index :uint = ((_firstIndex + index) % _capacity);
            return _array[index];
        }
    }

    /**
     * Executes a test function on each item in the ring buffer
     * until an item is reached that returns false for the specified
     * function.
     *
     * Returns a Boolean value of true if all items in the buffer return
     * true for the specified function; otherwise, false.
     */
    public function every (callback :Function, thisObject :* = null) :Boolean
    {
        for (var i :int = 0; i < _length; ++i) {
            if (!callback.apply(thisObject, this.at(i))) {
                return false;
            }
        }

        return true;
    }

    /**
     * Executes a function on each item in the ring buffer.
     */
    public function forEach (callback :Function, thisObject :* = null) :void
    {
        for (var i :int = 0; i < _length; ++i) {
            callback.apply(thisObject, this.at(i));
        }
    }

    /**
     * Searches for an item in the ring buffer by using strict equality
     * (===) and returns the index position of the item, or -1
     * if the item is not found.
     */
    public function indexOf (searchElement :*, fromIndex :int = 0) :int
    {
        for (var i :int = 0; i < _length; ++i) {
            if (this.at(i) === searchElement) {
                return i;
            }
        }

        return -1;
    }

    protected var _array :Array = new Array();
    protected var _capacity :uint;
    protected var _length :uint;
    protected var _firstIndex :uint;
}

}

//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// 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.util {

public class RingBuffer
{
    /** Creates a new RingBuffer with the specified capacity. */
    public function RingBuffer (capacity :uint = 1)
    {
        _capacity = capacity;
        _array.length = _capacity;
    }

    /** Returns the capacity of the RingBuffer. */
    public function get capacity () :uint
    {
        return _capacity;
    }

    /**
     * Sets the capacity of the RingBuffer.
     * If the new capacity is less than the RingBuffer's length,
     * elements will be removed from the end of the RingBuffer
     * to accommodate the smaller capacity.
     */
    public function set capacity (newCapacity :uint) :void
    {
        // Copy all the elements to a new array.
        var newArray :Array = new Array();
        var newLength :uint = Math.min(_length, newCapacity);
        newArray.length = newCapacity;
        for (var i :uint = 0; i < newLength; ++i) {
            newArray[i] = this.at(i);
        }

        _capacity = newCapacity;
        _length = newLength;
        _array = newArray;
        _firstIndex = 0;
    }

    /** Returns the number of elements currently stored in the RingBuffer. */
    public function get length () :uint
    {
        return _length;
    }

    /** Returns true if the RingBuffer contains 0 elements. */
    public function get empty () :Boolean
    {
        return (0 == _length);
    }

    /**
     * Adds the specified elements to the front of the RingBuffer.
     * If the RingBuffer's length is equal to its capacity, this
     * will cause elements to be removed from the back of
     * the RingBuffer.
     * Returns the new length of the RingBuffer.
     */
    public function unshift (...args) :uint
    {
        for (var i :int = args.length - 1; i >= 0; --i) {
            var index :uint = (_firstIndex > 0 ? _firstIndex - 1 : _capacity - 1);
            _array[index] = args[i];
            _length = Math.min(_length + 1, _capacity);
            _firstIndex = index;
        }

        return _length;
    }

    /**
     * Adds the specified elements to the back of the RingBuffer.
     * If the RingBuffer's length is equal to its capacity, this
     * will cause a elements to be removed from the front of
     * the RingBuffer.
     * Returns the new length of the RingBuffer.
     */
    public function push (...args) :uint
    {
        for (var i :uint = 0; i < args.length; ++i) {
            var index :uint = ((_firstIndex + _length) % _capacity);
            _array[index] = args[i];
            _length = Math.min(_length + 1, _capacity);

            // did we overwrite the first index?
            if (index == _firstIndex && _length == _capacity) {
                _firstIndex = (_firstIndex < _capacity - 1 ? _firstIndex + 1 : 0);
            }
        }

        return _length;
    }

    /**
     * Removes the first element from the RingBuffer and returns it.
     * If the RingBuffer is empty, shift() will return undefined.
     */
    public function shift () :*
    {
        if (this.empty) {
            return undefined;
        }

        var obj :* = _array[_firstIndex];
        _array[_firstIndex] = undefined;
        _firstIndex = (_firstIndex < _capacity - 1 ? _firstIndex + 1 : 0);
        --_length;

        return obj;
    }

    /**
     * Removes the last element from the RingBuffer and returns it.
     * If the RingBuffer is empty, pop() will return undefined.
     */
    public function pop () :*
    {
        if (this.empty) {
            return undefined;
        }

        var lastIndex :uint = ((_firstIndex + _length - 1) % _capacity);

        var obj :* = _array[lastIndex];
        _array[lastIndex] = undefined;
        --_length;

        return obj;
    }

    /** Removes all elements from the RingBuffer. */
    public function clear () :void
    {
        _array = new Array();
        _array.length = _capacity;
        _length = 0;
        _firstIndex = 0;
    }

    /**
     * Returns the element at the specified index.
     * If index >= length, at() will return undefined.
     */
    public function at (index :uint) :*
    {
        if (index >= _length) {
            return undefined;
        } else {
            var index :uint = ((_firstIndex + index) % _capacity);
            return _array[index];
        }
    }

    /**
     * Executes a test function on each item in the ring buffer
     * until an item is reached that returns false for the specified
     * function.
     *
     * Returns a Boolean value of true if all items in the buffer return
     * true for the specified function; otherwise, false.
     */
    public function every (callback :Function, thisObject :* = null) :Boolean
    {
        for (var i :int = 0; i < _length; ++i) {
            if (!callback.call(thisObject, this.at(i))) {
                return false;
            }
        }

        return true;
    }

    /**
     * Executes a function on each item in the ring buffer.
     */
    public function forEach (callback :Function, thisObject :* = null) :void
    {
        for (var i :int = 0; i < _length; ++i) {
            callback.call(thisObject, this.at(i));
        }
    }

    /**
     * Searches for an item in the ring buffer by using strict equality
     * (===) and returns the index position of the item, or -1
     * if the item is not found.
     */
    public function indexOf (searchElement :*, fromIndex :int = 0) :int
    {
        for (var i :int = 0; i < _length; ++i) {
            if (this.at(i) === searchElement) {
                return i;
            }
        }

        return -1;
    }

    protected var _array :Array = new Array();
    protected var _capacity :uint;
    protected var _length :uint;
    protected var _firstIndex :uint;
}

}

use Function.call(), not Function.apply()

git-svn-id: a1a4b28b82a3276cc491891159dd9963a0a72fae@4941 542714f4-19e9-0310-aa3c-eee0fc999fb1


package aerys.minko.type
{
	public final class Signal
	{
		private var _name			: String			= null;

		private var _callbacks		: Array				= [];
		private var _numCallbacks	: uint				= 0;

		private var _executed		: Boolean			= false;
		private var _numAdded		: uint				= 0;
		private var _toAdd			: Array				= null;
		private var _numRemoved		: uint				= 0;
		private var _toRemove		: Array				= null;

		public function get numCallbacks() : uint
		{
			return _numCallbacks;
		}

		public function Signal(name : String)
		{
			_name = name;
		}

		public function add(callback : Function) : void
		{
			if (_executed)
			{
				if (_toAdd)
					_toAdd.push(callback);
				else
					_toAdd = [callback];
				++_numAdded;

				return ;
			}

			_callbacks[_numCallbacks] = callback;
			++_numCallbacks;
		}

		public function remove(callback : Function) : void
		{
			if (_executed)
			{
				if (_toRemove)
					_toRemove.push(callback);
				else
					_toRemove = [callback];
				++_numRemoved;

				return ;
			}

			var index : int = _callbacks.indexOf(callback);

			if (index < 0)
				throw new Error("This callback does not exist.");

			--_numCallbacks;
			_callbacks[index] = _callbacks[_numCallbacks];
			_callbacks.length = _numCallbacks;
		}

		public function hasCallback(callback : Function) : Boolean
		{
			return _callbacks.indexOf(callback) >= 0;
		}

		public function execute(...params) : void
		{
			_executed = true;
			for (var i : uint = 0; i < _numCallbacks; ++i)
				(_callbacks[i] as Function).apply(null, params);
			_executed = false;

			for (i = 0; i < _numAdded; ++i)
				add(_toAdd[i]);
			_numAdded = 0;
			_toAdd = null;

			for (i = 0; i < _numRemoved; ++i)
				remove(_toRemove[i]);
			_numRemoved = 0;
			_toRemove = null;
		}
	}
}

package aerys.minko.type
{
	public final class Signal
	{
		private var _name			: String			= null;

		private var _callbacks		: Array				= [];
		private var _numCallbacks	: uint				= 0;

		private var _executed		: Boolean			= false;
		private var _numAdded		: uint				= 0;
		private var _toAdd			: Array				= null;
		private var _numRemoved		: uint				= 0;
		private var _toRemove		: Array				= null;

		public function get numCallbacks() : uint
		{
			return _numCallbacks;
		}

		public function Signal(name : String)
		{
			_name = name;
		}

		public function removeAllCallback() : void
		{
			for (var callbackIndex : int = _numCallbacks - 1; callbackIndex >= 0; --callbackIndex)
				remove(_callbacks[callbackIndex]);
		}

		public function add(callback : Function) : void
		{
			if (_executed)
			{
				if (_toAdd)
					_toAdd.push(callback);
				else
					_toAdd = [callback];
				++_numAdded;

				return ;
			}

			_callbacks[_numCallbacks] = callback;
			++_numCallbacks;
		}

		public function remove(callback : Function) : void
		{
			if (_executed)
			{
				if (_toRemove)
					_toRemove.push(callback);
				else
					_toRemove = [callback];
				++_numRemoved;

				return ;
			}

			var index : int = _callbacks.indexOf(callback);

			if (index < 0)
				throw new Error("This callback does not exist.");

			--_numCallbacks;
			_callbacks[index] = _callbacks[_numCallbacks];
			_callbacks.length = _numCallbacks;
		}

		public function hasCallback(callback : Function) : Boolean
		{
			return _callbacks.indexOf(callback) >= 0;
		}

		public function execute(...params) : void
		{
			_executed = true;
			for (var i : uint = 0; i < _numCallbacks; ++i)
				(_callbacks[i] as Function).apply(null, params);
			_executed = false;

			for (i = 0; i < _numAdded; ++i)
				add(_toAdd[i]);
			_numAdded = 0;
			_toAdd = null;

			for (i = 0; i < _numRemoved; ++i)
				remove(_toRemove[i]);
			_numRemoved = 0;
			_toRemove = null;
		}
	}
}

Add removeAllCallback method for Signal

Add removeAllCallback method for Signal


//
// $Id$

package com.threerings.flash {

import flash.display.Loader;

/**
 * Contains a utility method for safely unloading a Loader.
 */
public class LoaderUtil
{
    /**
     * Safely unload the specified loader.
     */
    public static function unload (loader :Loader) :void
    {
        try {
            loader.close();
        } catch (e1 :Error) {
            // ignore
        }
//        try {
//            loader.unloadAndStop();
//        } catch (e2 :Error) {
            // hmm, maybe they are using FP9 still
            try {
                loader.unload();
            } catch (e3 :Error) {
                // ignore
            }
//        }
    }
}
}

//
// $Id$

package com.threerings.flash {

import flash.display.Loader;

/**
 * Contains a utility method for safely unloading a Loader.
 */
public class LoaderUtil
{
    /**
     * Safely unload the specified loader.
     */
    public static function unload (loader :Loader) :void
    {
        try {
            loader.close();
        } catch (e1 :Error) {
            // ignore
        }
        try {
            loader.unloadAndStop();
        } catch (e2 :Error) {
            // hmm, maybe they are using FP9 still
            try {
                loader.unload();
            } catch (e3 :Error) {
                // ignore
            }
        }
    }
}
}

Enable glorious unloadAndStop().
I did some tests with it, and it sure does put the kibosh on things.

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


/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the at.matthew.httpstreaming package.
 *
 * The Initial Developer of the Original Code is
 * Matthew Kaufman.
 * Portions created by the Initial Developer are Copyright (C) 2011
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * ***** END LICENSE BLOCK ***** */

package org.denivip.osmf.net.httpstreaming.hls
{
	import flash.utils.ByteArray;
	import flash.utils.IDataInput;

	import com.hurlant.util.Hex;
	import org.denivip.osmf.utility.decrypt.AES;
	import org.osmf.logging.Log;
	import org.osmf.logging.Logger;
	import org.osmf.net.httpstreaming.HTTPStreamingFileHandlerBase;

	[Event(name="notifySegmentDuration", type="org.osmf.events.HTTPStreamingFileHandlerEvent")]
	[Event(name="notifyTimeBias", type="org.osmf.events.HTTPStreamingFileHandlerEvent")]

	public class HTTPStreamingMP2TSFileHandler extends HTTPStreamingFileHandlerBase
	{
		private var _syncFound:Boolean;
		private var _pmtPID:uint;
		private var _audioPID:uint;
		private var _videoPID:uint;
		private var _mp3AudioPID:uint;
		private var _audioPES:HTTPStreamingMP2PESAudio;
		private var _videoPES:HTTPStreamingMP2PESVideo;
		private var _mp3audioPES:HTTPStreamingMp3Audio2ToPESAudio;

		private var _cachedOutputBytes:ByteArray;
		private var alternatingYieldCounter:int = 0;

		private var _key:HTTPStreamingM3U8IndexKey = null;
		private var _iv:ByteArray = null;
		private var _decryptBuffer:ByteArray = new ByteArray;

		// AES-128 specific variables
		private var _decryptAES:AES = null;

		public function HTTPStreamingMP2TSFileHandler()
		{
			_audioPES = new HTTPStreamingMP2PESAudio;
			_videoPES = new HTTPStreamingMP2PESVideo;
			_mp3audioPES = new HTTPStreamingMp3Audio2ToPESAudio;
		}

		override public function beginProcessFile(seek:Boolean, seekTime:Number):void
		{
			_syncFound = false;
		}

		override public function get inputBytesNeeded():Number
		{
			return _syncFound ? 187 : 1;
		}

		override public function processFileSegment(input:IDataInput):ByteArray
		{
			var bytesAvailableStart:uint = input.bytesAvailable;
			var output:ByteArray;

			if (_cachedOutputBytes !== null) {
				output = _cachedOutputBytes;
				_cachedOutputBytes = null;
			}
			else {
				output = new ByteArray();
			}

			while (true) {
				if(!_syncFound)
				{
					if (_key) {
						if (_key.type == "AES-128") {
							if (input.bytesAvailable < 16) {
								if (_decryptBuffer.bytesAvailable < 1) {
									break;
								}
							} else {
								if (!decryptToBuffer(input, 16)) {
									break;
								}
							}
							if (_decryptBuffer.readByte() == 0x47) {
								_syncFound = true;
							}
						}
					} else {
						if(input.bytesAvailable < 1)
							break;

						if(input.readByte() == 0x47)
							_syncFound = true;
					}
				}
				else
				{
					_syncFound = false;
					var packet:ByteArray = new ByteArray();

					if (_key) {
						if (_key.type == "AES-128") {
							if (input.bytesAvailable < 176) {
								if (_decryptBuffer.bytesAvailable < 187) {
									break;
								}
							} else {
								var bytesLeft:uint = input.bytesAvailable - 176;
								if (bytesLeft > 0 && bytesLeft < 15) {
									if (!decryptToBuffer(input, input.bytesAvailable)) {
										break;
									}
								} else {
									if (!decryptToBuffer(input, 176)) {
										break;
									}
								}
							}
							_decryptBuffer.readBytes(packet, 0, 187);
						}
					} else {
						if(input.bytesAvailable < 187)
							break;

						input.readBytes(packet, 0, 187);
					}

					var result:ByteArray = processPacket(packet);
					if (result !== null) {
						output.writeBytes(result);
					}

					if (bytesAvailableStart - input.bytesAvailable > 10000) {
						alternatingYieldCounter = (alternatingYieldCounter + 1) & 0x03;
						if (alternatingYieldCounter /*& 0x01 === 1*/) {
							_cachedOutputBytes = output;
							return null;
						}
						break;
					}
				}
			}
			output.position = 0;

			return output.length === 0 ? null : output;
		}

		private function decryptToBuffer(input:IDataInput, blockSize:int):Boolean{
			if (_key) {
				// Clear buffer
				if (_decryptBuffer.bytesAvailable == 0) {
					_decryptBuffer.clear();
				}

				if (_key.type == "AES-128" && blockSize % 16 == 0 && _key.key) {
					if (!_decryptAES) {
						_decryptAES = new AES(_key.key);
						_decryptAES.pad = "none";
						_decryptAES.iv = _iv;
					}

					// Save buffer position
					var currentPosition:uint = _decryptBuffer.position;
					_decryptBuffer.position += _decryptBuffer.bytesAvailable;

					// Save block to decrypt
					var decrypt:ByteArray = new ByteArray;
					input.readBytes(decrypt, 0, blockSize);
					// Save new IV from ciphertext
					var newIv:ByteArray = new ByteArray;
					decrypt.position += (decrypt.bytesAvailable-16);
					decrypt.readBytes(newIv, 0, 16);
					decrypt.position = 0;
					// Decrypt
					if (input.bytesAvailable == 0) {
						_decryptAES.pad = "pkcs7";
					}
					_decryptAES.decrypt(decrypt);
					decrypt.position = 0;
					// Write into buffer
					_decryptBuffer.writeBytes(decrypt);
					_decryptBuffer.position = currentPosition;
					// Update AES IV
					_decryptAES.iv = newIv;

					return true;
				}
			}

			return false;
		}

		override public function endProcessFile(input:IDataInput):ByteArray
		{
			_decryptBuffer.clear();
			if (_decryptAES) {
				_decryptAES.destroy();
			}
			_decryptAES = null;
			return null;
		}

		public function resetCache():void{
			_cachedOutputBytes = null;
			alternatingYieldCounter = 0;
			_decryptBuffer.clear();
			if (_decryptAES) {
				_decryptAES.destroy();
			}
			_decryptAES = null;
		}

		public function set initialOffset(offset:Number):void{
			offset *= 1000; // convert to ms
			_videoPES.initialTimestamp = offset;
			_audioPES.initialTimestamp = offset;
			_mp3audioPES.initialTimestamp = offset;
		}

		public function set key(key:HTTPStreamingM3U8IndexKey):void {
			_key = key;
			if (_decryptAES) {
				_decryptAES.destroy();
			}
			_decryptAES = null;
		}

		public function set iv(iv:String):void {
			if (iv) {
				_iv = Hex.toArray(iv);
			}
		}

		private function processPacket(packet:ByteArray):ByteArray
		{
			// decode rest of transport stream prefix (after the 0x47 flag byte)

			// top of second byte
			var value:uint = packet.readUnsignedByte();

			//var tei:Boolean = Boolean(value & 0x80);	// error indicator
			var pusi:Boolean = Boolean(value & 0x40);	// payload unit start indication
			//var tpri:Boolean = Boolean(value & 0x20);	// transport priority indication

			// bottom of second byte and all of third
			value <<= 8;
			value += packet.readUnsignedByte();

			var pid:uint = value & 0x1fff;	// packet ID

			// fourth byte
			value = packet.readUnsignedByte();
			//var scramblingControl:uint = (value >> 6) & 0x03;	// scrambling control bits
			var hasAF:Boolean = Boolean(value & 0x20);	// has adaptation field
			var hasPD:Boolean = Boolean(value & 0x10);	// has payload data
			//var ccount:uint = value & 0x0f;		// continuty count

			// technically hasPD without hasAF is an error, see spec

			if(hasAF)
			{
				// process adaptation field
				// don't care about flags
				// don't care about clocks here
                var af:uint = packet.readUnsignedByte();
				packet.position += af;	// skip to end
			}

            return hasPD ? processES(pid, pusi, packet) : null;
		}

		private function processES(pid:uint, pusi:Boolean, packet:ByteArray):ByteArray
		{
			var output:ByteArray = null;
			if(pid == 0)	// PAT
			{
				if(pusi)
					processPAT(packet);
			}
			else if(pid == _pmtPID)
			{
				if(pusi)
					processPMT(packet);
			}
			else if(pid == _audioPID)
			{
				output = _audioPES.processES(pusi, packet);
			}
			else if(pid == _videoPID)
			{
				output = _videoPES.processES(pusi, packet);
			}
			else if(pid == _mp3AudioPID)
			{
				output = _mp3audioPES.processES(pusi, packet);
			}

			return output;
		}

		private function processPAT(packet:ByteArray):void
		{
			packet.readUnsignedByte();   // pointer:uint
			packet.readUnsignedByte();   // tableID:uint
			var remaining:uint = packet.readUnsignedShort() & 0x03ff; // ignoring misc and reserved bits

			packet.position += 5; // skip tsid + version/cni + sec# + last sec#
			remaining -= 5;

			while(remaining > 4)
			{
				packet.readUnsignedShort(); // program number
				_pmtPID = packet.readUnsignedShort() & 0x1fff; // 13 bits
				remaining -= 4;

				//return; // immediately after reading the first pmt ID, if we don't we get the LAST one
			}

			// and ignore the CRC (4 bytes)
		}

		private function processPMT(packet:ByteArray):void
		{
			packet.readUnsignedByte();  // pointer:uint
			var tableID:uint = packet.readUnsignedByte();

			if (tableID != 0x02)
			{
				CONFIG::LOGGING
				{
					logger.warn("PAT pointed to PMT that isn't PMT");
				}
				return; // don't try to parse it
			}

			var remaining:uint = packet.readUnsignedShort() & 0x03ff; // ignoring section syntax and reserved

			packet.position += 7; // skip program num, rserved, version, cni, section num, last section num, reserved, PCR PID
			remaining -= 7;

			var piLen:uint = packet.readUnsignedShort() & 0x0fff;
			remaining -= 2;

			packet.position += piLen; // skip program info
			remaining -= piLen;

			while(remaining > 4)
			{
				var type:uint = packet.readUnsignedByte();
				var pid:uint = packet.readUnsignedShort() & 0x1fff;
				var esiLen:uint = packet.readUnsignedShort() & 0x0fff;
				remaining -= 5;

				packet.position += esiLen;
				remaining -= esiLen;

				switch(type)
				{
					case 0x1b: // H.264 video
						_videoPID = pid;
						break;
					case 0x0f: // AAC Audio / ADTS
						_audioPID = pid;
						break;

					case 0x03: // MP3 Audio  (3 & 4)
					case 0x04:
						_mp3AudioPID = pid;
						break;

					default:
						CONFIG::LOGGING
						{
							logger.error("unsupported type "+type.toString(16)+" in PMT");
						}
						break;
				}
			}

			// and ignore CRC
		}

		override public function flushFileSegment(input:IDataInput):ByteArray
		{
			var flvBytes:ByteArray = new ByteArray();
			var flvBytesVideo:ByteArray = _videoPES.processES(false, null, true);
			var flvBytesAudio:ByteArray = _audioPES.processES(false, null, true);

			if(flvBytesVideo)
				flvBytes.readBytes(flvBytesVideo);
			if(flvBytesAudio)
				flvBytes.readBytes(flvBytesAudio);

			return flvBytes;
		}

		CONFIG::LOGGING
		{
			private var logger:Logger = Log.getLogger('org.denivip.osmf.net.httpstreaming.hls.HTTPStreamingMP2TSFileHandler') as Logger;
		}
	}
}

/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the at.matthew.httpstreaming package.
 *
 * The Initial Developer of the Original Code is
 * Matthew Kaufman.
 * Portions created by the Initial Developer are Copyright (C) 2011
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * ***** END LICENSE BLOCK ***** */

package org.denivip.osmf.net.httpstreaming.hls
{
	import flash.utils.ByteArray;
	import flash.utils.IDataInput;

	import com.hurlant.util.Hex;
	import org.denivip.osmf.utility.decrypt.AES;
	import org.osmf.logging.Log;
	import org.osmf.logging.Logger;
	import org.osmf.net.httpstreaming.HTTPStreamingFileHandlerBase;

	[Event(name="notifySegmentDuration", type="org.osmf.events.HTTPStreamingFileHandlerEvent")]
	[Event(name="notifyTimeBias", type="org.osmf.events.HTTPStreamingFileHandlerEvent")]

	public class HTTPStreamingMP2TSFileHandler extends HTTPStreamingFileHandlerBase
	{
		private var _syncFound:Boolean;
		private var _pmtPID:uint;
		private var _audioPID:uint;
		private var _videoPID:uint;
		private var _mp3AudioPID:uint;
		private var _audioPES:HTTPStreamingMP2PESAudio;
		private var _videoPES:HTTPStreamingMP2PESVideo;
		private var _mp3audioPES:HTTPStreamingMp3Audio2ToPESAudio;

		private var _cachedOutputBytes:ByteArray;
		private var alternatingYieldCounter:int = 0;

		private var _key:HTTPStreamingM3U8IndexKey = null;
		private var _iv:ByteArray = null;
		private var _decryptBuffer:ByteArray = new ByteArray;

		// AES-128 specific variables
		private var _decryptAES:AES = null;

		public function HTTPStreamingMP2TSFileHandler()
		{
			_audioPES = new HTTPStreamingMP2PESAudio;
			_videoPES = new HTTPStreamingMP2PESVideo;
			_mp3audioPES = new HTTPStreamingMp3Audio2ToPESAudio;
		}

		override public function beginProcessFile(seek:Boolean, seekTime:Number):void
		{
			_syncFound = false;
		}

		override public function get inputBytesNeeded():Number
		{
			return _syncFound ? 187 : 1;
		}

		override public function processFileSegment(input:IDataInput):ByteArray
		{
			var bytesAvailableStart:uint = input.bytesAvailable;
			var output:ByteArray;

			if (_cachedOutputBytes !== null) {
				output = _cachedOutputBytes;
				_cachedOutputBytes = null;
			}
			else {
				output = new ByteArray();
			}

			while (true) {
				if(!_syncFound)
				{
					if (_key) {
						if (_key.type == "AES-128") {
							if (input.bytesAvailable < 16) {
								if (_decryptBuffer.bytesAvailable < 1) {
									break;
								}
							} else {
								if (!decryptToBuffer(input, 16)) {
									break;
								}
							}
							if (_decryptBuffer.readByte() == 0x47) {
								_syncFound = true;
							}
						}
					} else {
						if(input.bytesAvailable < 1)
							break;

						if(input.readByte() == 0x47)
							_syncFound = true;
					}
				}
				else
				{
					var packet:ByteArray = new ByteArray();

					if (_key) {
						if (_key.type == "AES-128") {
							if (input.bytesAvailable < 176) {
								if (_decryptBuffer.bytesAvailable < 187) {
									break;
								}
							} else {
								var bytesLeft:uint = input.bytesAvailable - 176;
								if (bytesLeft > 0 && bytesLeft < 15) {
									if (!decryptToBuffer(input, input.bytesAvailable)) {
										break;
									}
								} else {
									if (!decryptToBuffer(input, 176)) {
										break;
									}
								}
							}
							_decryptBuffer.readBytes(packet, 0, 187);
						}
					} else {
						if(input.bytesAvailable < 187)
							break;

						input.readBytes(packet, 0, 187);
					}

					_syncFound = false;
					var result:ByteArray = processPacket(packet);
					if (result !== null) {
						output.writeBytes(result);
					}

					if (bytesAvailableStart - input.bytesAvailable > 10000) {
						alternatingYieldCounter = (alternatingYieldCounter + 1) & 0x03;
						if (alternatingYieldCounter /*& 0x01 === 1*/) {
							_cachedOutputBytes = output;
							return null;
						}
						break;
					}
				}
			}
			output.position = 0;

			return output.length === 0 ? null : output;
		}

		private function decryptToBuffer(input:IDataInput, blockSize:int):Boolean{
			if (_key) {
				// Clear buffer
				if (_decryptBuffer.bytesAvailable == 0) {
					_decryptBuffer.clear();
				}

				if (_key.type == "AES-128" && blockSize % 16 == 0 && _key.key) {
					if (!_decryptAES) {
						_decryptAES = new AES(_key.key);
						_decryptAES.pad = "none";
						_decryptAES.iv = _iv;
					}

					// Save buffer position
					var currentPosition:uint = _decryptBuffer.position;
					_decryptBuffer.position += _decryptBuffer.bytesAvailable;

					// Save block to decrypt
					var decrypt:ByteArray = new ByteArray;
					input.readBytes(decrypt, 0, blockSize);
					// Save new IV from ciphertext
					var newIv:ByteArray = new ByteArray;
					decrypt.position += (decrypt.bytesAvailable-16);
					decrypt.readBytes(newIv, 0, 16);
					decrypt.position = 0;
					// Decrypt
					if (input.bytesAvailable == 0) {
						_decryptAES.pad = "pkcs7";
					}
					_decryptAES.decrypt(decrypt);
					decrypt.position = 0;
					// Write into buffer
					_decryptBuffer.writeBytes(decrypt);
					_decryptBuffer.position = currentPosition;
					// Update AES IV
					_decryptAES.iv = newIv;

					return true;
				}
			}

			return false;
		}

		override public function endProcessFile(input:IDataInput):ByteArray
		{
			_decryptBuffer.clear();
			if (_decryptAES) {
				_decryptAES.destroy();
			}
			_decryptAES = null;
			return null;
		}

		public function resetCache():void{
			_cachedOutputBytes = null;
			alternatingYieldCounter = 0;
			_decryptBuffer.clear();
			if (_decryptAES) {
				_decryptAES.destroy();
			}
			_decryptAES = null;
		}

		public function set initialOffset(offset:Number):void{
			offset *= 1000; // convert to ms
			_videoPES.initialTimestamp = offset;
			_audioPES.initialTimestamp = offset;
			_mp3audioPES.initialTimestamp = offset;
		}

		public function set key(key:HTTPStreamingM3U8IndexKey):void {
			_key = key;
			if (_decryptAES) {
				_decryptAES.destroy();
			}
			_decryptAES = null;
		}

		public function set iv(iv:String):void {
			if (iv) {
				_iv = Hex.toArray(iv);
			}
		}

		private function processPacket(packet:ByteArray):ByteArray
		{
			// decode rest of transport stream prefix (after the 0x47 flag byte)

			// top of second byte
			var value:uint = packet.readUnsignedByte();

			//var tei:Boolean = Boolean(value & 0x80);	// error indicator
			var pusi:Boolean = Boolean(value & 0x40);	// payload unit start indication
			//var tpri:Boolean = Boolean(value & 0x20);	// transport priority indication

			// bottom of second byte and all of third
			value <<= 8;
			value += packet.readUnsignedByte();

			var pid:uint = value & 0x1fff;	// packet ID

			// fourth byte
			value = packet.readUnsignedByte();
			//var scramblingControl:uint = (value >> 6) & 0x03;	// scrambling control bits
			var hasAF:Boolean = Boolean(value & 0x20);	// has adaptation field
			var hasPD:Boolean = Boolean(value & 0x10);	// has payload data
			//var ccount:uint = value & 0x0f;		// continuty count

			// technically hasPD without hasAF is an error, see spec

			if(hasAF)
			{
				// process adaptation field
				// don't care about flags
				// don't care about clocks here
                var af:uint = packet.readUnsignedByte();
				packet.position += af;	// skip to end
			}

            return hasPD ? processES(pid, pusi, packet) : null;
		}

		private function processES(pid:uint, pusi:Boolean, packet:ByteArray):ByteArray
		{
			var output:ByteArray = null;
			if(pid == 0)	// PAT
			{
				if(pusi)
					processPAT(packet);
			}
			else if(pid == _pmtPID)
			{
				if(pusi)
					processPMT(packet);
			}
			else if(pid == _audioPID)
			{
				output = _audioPES.processES(pusi, packet);
			}
			else if(pid == _videoPID)
			{
				output = _videoPES.processES(pusi, packet);
			}
			else if(pid == _mp3AudioPID)
			{
				output = _mp3audioPES.processES(pusi, packet);
			}

			return output;
		}

		private function processPAT(packet:ByteArray):void
		{
			packet.readUnsignedByte();   // pointer:uint
			packet.readUnsignedByte();   // tableID:uint
			var remaining:uint = packet.readUnsignedShort() & 0x03ff; // ignoring misc and reserved bits

			packet.position += 5; // skip tsid + version/cni + sec# + last sec#
			remaining -= 5;

			while(remaining > 4)
			{
				packet.readUnsignedShort(); // program number
				_pmtPID = packet.readUnsignedShort() & 0x1fff; // 13 bits
				remaining -= 4;

				//return; // immediately after reading the first pmt ID, if we don't we get the LAST one
			}

			// and ignore the CRC (4 bytes)
		}

		private function processPMT(packet:ByteArray):void
		{
			packet.readUnsignedByte();  // pointer:uint
			var tableID:uint = packet.readUnsignedByte();

			if (tableID != 0x02)
			{
				CONFIG::LOGGING
				{
					logger.warn("PAT pointed to PMT that isn't PMT");
				}
				return; // don't try to parse it
			}

			var remaining:uint = packet.readUnsignedShort() & 0x03ff; // ignoring section syntax and reserved

			packet.position += 7; // skip program num, rserved, version, cni, section num, last section num, reserved, PCR PID
			remaining -= 7;

			var piLen:uint = packet.readUnsignedShort() & 0x0fff;
			remaining -= 2;

			packet.position += piLen; // skip program info
			remaining -= piLen;

			while(remaining > 4)
			{
				var type:uint = packet.readUnsignedByte();
				var pid:uint = packet.readUnsignedShort() & 0x1fff;
				var esiLen:uint = packet.readUnsignedShort() & 0x0fff;
				remaining -= 5;

				packet.position += esiLen;
				remaining -= esiLen;

				switch(type)
				{
					case 0x1b: // H.264 video
						_videoPID = pid;
						break;
					case 0x0f: // AAC Audio / ADTS
						_audioPID = pid;
						break;

					case 0x03: // MP3 Audio  (3 & 4)
					case 0x04:
						_mp3AudioPID = pid;
						break;

					default:
						CONFIG::LOGGING
						{
							logger.error("unsupported type "+type.toString(16)+" in PMT");
						}
						break;
				}
			}

			// and ignore CRC
		}

		override public function flushFileSegment(input:IDataInput):ByteArray
		{
			var flvBytes:ByteArray = new ByteArray();
			var flvBytesVideo:ByteArray = _videoPES.processES(false, null, true);
			var flvBytesAudio:ByteArray = _audioPES.processES(false, null, true);

			if(flvBytesVideo)
				flvBytes.readBytes(flvBytesVideo);
			if(flvBytesAudio)
				flvBytes.readBytes(flvBytesAudio);

			return flvBytes;
		}

		CONFIG::LOGGING
		{
			private var logger:Logger = Log.getLogger('org.denivip.osmf.net.httpstreaming.hls.HTTPStreamingMP2TSFileHandler') as Logger;
		}
	}
}

Fix bug where syncFound was flagged as false incorrectly

This was causing byte-level sync issues with throttled (and potentially
other) streams


package aerys.minko.render.material.basic
{
	import aerys.minko.render.Effect;
	import aerys.minko.render.material.Material;
	import aerys.minko.render.resource.texture.TextureResource;
	import aerys.minko.type.binding.IDataProvider;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Vector4;

	public class BasicMaterial extends Material
	{
		public static const DEFAULT_NAME			: String		= 'BasicMaterial';
		public static const DEFAULT_BASIC_SHADER	: BasicShader	= new BasicShader();
		public static const DEFAULT_EFFECT			: Effect		= new Effect(DEFAULT_BASIC_SHADER);

		public function get blending() : uint
		{
			return getProperty(BasicProperties.BLENDING);
		}
		public function set blending(value : uint) : void
		{
			setProperty(BasicProperties.BLENDING, value);
		}

		public function get triangleCulling() : uint
		{
			return getProperty(BasicProperties.TRIANGLE_CULLING);
		}
		public function set triangleCulling(value : uint) : void
		{
			setProperty(BasicProperties.TRIANGLE_CULLING, value);
		}

		public function get diffuseColor() : Object
		{
			return getProperty(BasicProperties.DIFFUSE_COLOR);
		}
		public function set diffuseColor(value : Object) : void
		{
			setProperty(BasicProperties.DIFFUSE_COLOR, value);
		}

		public function get diffuseMap() : TextureResource
		{
			return getProperty(BasicProperties.DIFFUSE_MAP);
		}
		public function set diffuseMap(value : TextureResource) : void
		{
			setProperty(BasicProperties.DIFFUSE_MAP, value);
		}

        public function get diffuseMapFiltering() : uint
        {
            return getProperty(BasicProperties.DIFFUSE_MAP_FILTERING);
        }
        public function set diffuseMapFiltering(value : uint) : void
        {
            setProperty(BasicProperties.DIFFUSE_MAP_FILTERING, value);
        }

        public function get diffuseMapMipMapping() : uint
        {
            return getProperty(BasicProperties.DIFFUSE_MAP_MIPMAPPING);
        }
        public function set diffuseMapMipMapping(value : uint) : void
        {
            setProperty(BasicProperties.DIFFUSE_MAP_MIPMAPPING, value);
        }

        public function get diffuseMapFormat() : uint
        {
            return getProperty(BasicProperties.DIFFUSE_MAP_FORMAT);
        }
        public function set diffuseMapFormat(value : uint) : void
        {
            setProperty(BasicProperties.DIFFUSE_MAP_FORMAT, value);
        }

		public function get alphaMap() : TextureResource
		{
			return getProperty(BasicProperties.ALPHA_MAP) as TextureResource;
		}
		public function set alphaMap(value : TextureResource) : void
		{
			setProperty(BasicProperties.ALPHA_MAP, value);
		}

		public function get alphaThreshold() : Number
		{
			return getProperty(BasicProperties.ALPHA_THRESHOLD);
		}
		public function set alphaThreshold(value : Number) : void
		{
			setProperty(BasicProperties.ALPHA_THRESHOLD, value);
		}

		public function get depthTest() : uint
		{
			return getProperty(BasicProperties.DEPTH_TEST);
		}
		public function set depthTest(value : uint) : void
		{
			setProperty(BasicProperties.DEPTH_TEST, value);
		}

		public function get depthWriteEnabled() : Boolean
		{
			return getProperty(BasicProperties.DEPTH_WRITE_ENABLED);
		}
		public function set depthWriteEnabled(value : Boolean) : void
		{
			setProperty(BasicProperties.DEPTH_WRITE_ENABLED, value);
		}

		public function get stencilTriangleFace() : uint
		{
			return getProperty(BasicProperties.STENCIL_TRIANGLE_FACE);
		}
		public function set stencilTriangleFace(value : uint) : void
		{
			setProperty(BasicProperties.STENCIL_TRIANGLE_FACE, value);
		}

		public function get stencilCompareMode() : uint
		{
			return getProperty(BasicProperties.STENCIL_COMPARE_MODE);
		}
		public function set stencilCompareMode(value : uint) : void
		{
			setProperty(BasicProperties.STENCIL_COMPARE_MODE, value);
		}

		public function get stencilActionBothPass() : uint
		{
			return getProperty(BasicProperties.STENCIL_ACTION_BOTH_PASS);
		}
		public function set stencilActionBothPass(value : uint) : void
		{
			setProperty(BasicProperties.STENCIL_ACTION_BOTH_PASS, value);
		}

		public function get stencilActionDepthFail() : uint
		{
			return getProperty(BasicProperties.STENCIL_ACTION_DEPTH_FAIL);
		}
		public function set stencilActionDepthFail(value : uint) : void
		{
			setProperty(BasicProperties.STENCIL_ACTION_DEPTH_FAIL, value);
		}

		public function get stencilActionDepthPassStencilFail() : uint
		{
			return getProperty(BasicProperties.STENCIL_ACTION_DEPTH_PASS_STENCIL_FAIL);
		}
		public function set stencilActionDepthPassStencilFail(value : uint) : void
		{
			setProperty(BasicProperties.STENCIL_ACTION_DEPTH_PASS_STENCIL_FAIL, value);
		}

		public function get stencilReferenceValue() : Number
		{
			return getProperty(BasicProperties.STENCIL_REFERENCE_VALUE);
		}
		public function set stencilReferenceValue(value : Number) : void
		{
			setProperty(BasicProperties.STENCIL_REFERENCE_VALUE, value);
		}

		public function get stencilReadMask() : uint
		{
			return getProperty(BasicProperties.STENCIL_READ_MASK);
		}
		public function set stencilReadMask(value : uint) : void
		{
			setProperty(BasicProperties.STENCIL_READ_MASK, value);
		}

		public function get stencilWriteMask() : uint
		{
			return getProperty(BasicProperties.STENCIL_WRITE_MASK);
		}
		public function set stencilWriteMask(value : uint) : void
		{
			setProperty(BasicProperties.STENCIL_WRITE_MASK, value);
		}

		public function get diffuseTransform() : Matrix4x4
		{
			return getProperty(BasicProperties.DIFFUSE_TRANSFORM);
		}
		public function set diffuseTransform(value : Matrix4x4) : void
		{
			setProperty(BasicProperties.DIFFUSE_TRANSFORM, value);
		}

        public function get uvOffset() : Vector4
        {
            return getProperty(BasicProperties.UV_OFFSET);
        }
        public function set uvOffset(value : Vector4) : void
        {
            setProperty(BasicProperties.UV_OFFSET, value);
        }

        public function get uvScale() : Vector4
        {
            return getProperty(BasicProperties.UV_SCALE);
        }
        public function set uvScale(value : Vector4) : void
        {
            setProperty(BasicProperties.UV_SCALE, value);
        }

		public function BasicMaterial(properties : Object = null, effect : Effect = null, name : String = DEFAULT_NAME)
		{
			super(effect || DEFAULT_EFFECT, properties, name);
		}

		override public function clone() : IDataProvider
		{
			var mat : BasicMaterial	= new BasicMaterial(this, effect, name);

			return mat;
		}
	}
}

package aerys.minko.render.material.basic
{
	import aerys.minko.render.Effect;
	import aerys.minko.render.material.Material;
	import aerys.minko.render.resource.texture.TextureResource;
	import aerys.minko.type.binding.IDataProvider;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Vector4;

	public class BasicMaterial extends Material
	{
		public static const DEFAULT_NAME			: String		= 'BasicMaterial';
		public static const DEFAULT_BASIC_SHADER	: BasicShader	= new BasicShader();
		public static const DEFAULT_EFFECT			: Effect		= new Effect(DEFAULT_BASIC_SHADER);

		public function get blending() : uint
		{
			return getProperty(BasicProperties.BLENDING);
		}
		public function set blending(value : uint) : void
		{
			setProperty(BasicProperties.BLENDING, value);
		}

		public function get triangleCulling() : uint
		{
			return getProperty(BasicProperties.TRIANGLE_CULLING);
		}
		public function set triangleCulling(value : uint) : void
		{
			setProperty(BasicProperties.TRIANGLE_CULLING, value);
		}

		public function get diffuseColor() : Object
		{
			return getProperty(BasicProperties.DIFFUSE_COLOR);
		}
		public function set diffuseColor(value : Object) : void
		{
			setProperty(BasicProperties.DIFFUSE_COLOR, value);
		}

		public function get diffuseMap() : TextureResource
		{
			return getProperty(BasicProperties.DIFFUSE_MAP);
		}
		public function set diffuseMap(value : TextureResource) : void
		{
			setProperty(BasicProperties.DIFFUSE_MAP, value);
		}

        public function get diffuseMapFiltering() : uint
        {
            return getProperty(BasicProperties.DIFFUSE_MAP_FILTERING);
        }
        public function set diffuseMapFiltering(value : uint) : void
        {
            setProperty(BasicProperties.DIFFUSE_MAP_FILTERING, value);
        }

        public function get diffuseMapMipMapping() : uint
        {
            return getProperty(BasicProperties.DIFFUSE_MAP_MIPMAPPING);
        }
        public function set diffuseMapMipMapping(value : uint) : void
        {
            setProperty(BasicProperties.DIFFUSE_MAP_MIPMAPPING, value);
        }

        public function get diffuseMapWrapping() : uint
        {
            return getProperty(BasicProperties.DIFFUSE_MAP_WRAPPING);
        }
        public function set diffuseMapWrapping(value : uint) : void
        {
            setProperty(BasicProperties.DIFFUSE_MAP_WRAPPING, value);
        }

        public function get diffuseMapFormat() : uint
        {
            return getProperty(BasicProperties.DIFFUSE_MAP_FORMAT);
        }
        public function set diffuseMapFormat(value : uint) : void
        {
            setProperty(BasicProperties.DIFFUSE_MAP_FORMAT, value);
        }

		public function get alphaMap() : TextureResource
		{
			return getProperty(BasicProperties.ALPHA_MAP) as TextureResource;
		}
		public function set alphaMap(value : TextureResource) : void
		{
			setProperty(BasicProperties.ALPHA_MAP, value);
		}

		public function get alphaThreshold() : Number
		{
			return getProperty(BasicProperties.ALPHA_THRESHOLD);
		}
		public function set alphaThreshold(value : Number) : void
		{
			setProperty(BasicProperties.ALPHA_THRESHOLD, value);
		}

		public function get depthTest() : uint
		{
			return getProperty(BasicProperties.DEPTH_TEST);
		}
		public function set depthTest(value : uint) : void
		{
			setProperty(BasicProperties.DEPTH_TEST, value);
		}

		public function get depthWriteEnabled() : Boolean
		{
			return getProperty(BasicProperties.DEPTH_WRITE_ENABLED);
		}
		public function set depthWriteEnabled(value : Boolean) : void
		{
			setProperty(BasicProperties.DEPTH_WRITE_ENABLED, value);
		}

		public function get stencilTriangleFace() : uint
		{
			return getProperty(BasicProperties.STENCIL_TRIANGLE_FACE);
		}
		public function set stencilTriangleFace(value : uint) : void
		{
			setProperty(BasicProperties.STENCIL_TRIANGLE_FACE, value);
		}

		public function get stencilCompareMode() : uint
		{
			return getProperty(BasicProperties.STENCIL_COMPARE_MODE);
		}
		public function set stencilCompareMode(value : uint) : void
		{
			setProperty(BasicProperties.STENCIL_COMPARE_MODE, value);
		}

		public function get stencilActionBothPass() : uint
		{
			return getProperty(BasicProperties.STENCIL_ACTION_BOTH_PASS);
		}
		public function set stencilActionBothPass(value : uint) : void
		{
			setProperty(BasicProperties.STENCIL_ACTION_BOTH_PASS, value);
		}

		public function get stencilActionDepthFail() : uint
		{
			return getProperty(BasicProperties.STENCIL_ACTION_DEPTH_FAIL);
		}
		public function set stencilActionDepthFail(value : uint) : void
		{
			setProperty(BasicProperties.STENCIL_ACTION_DEPTH_FAIL, value);
		}

		public function get stencilActionDepthPassStencilFail() : uint
		{
			return getProperty(BasicProperties.STENCIL_ACTION_DEPTH_PASS_STENCIL_FAIL);
		}
		public function set stencilActionDepthPassStencilFail(value : uint) : void
		{
			setProperty(BasicProperties.STENCIL_ACTION_DEPTH_PASS_STENCIL_FAIL, value);
		}

		public function get stencilReferenceValue() : Number
		{
			return getProperty(BasicProperties.STENCIL_REFERENCE_VALUE);
		}
		public function set stencilReferenceValue(value : Number) : void
		{
			setProperty(BasicProperties.STENCIL_REFERENCE_VALUE, value);
		}

		public function get stencilReadMask() : uint
		{
			return getProperty(BasicProperties.STENCIL_READ_MASK);
		}
		public function set stencilReadMask(value : uint) : void
		{
			setProperty(BasicProperties.STENCIL_READ_MASK, value);
		}

		public function get stencilWriteMask() : uint
		{
			return getProperty(BasicProperties.STENCIL_WRITE_MASK);
		}
		public function set stencilWriteMask(value : uint) : void
		{
			setProperty(BasicProperties.STENCIL_WRITE_MASK, value);
		}

		public function get diffuseTransform() : Matrix4x4
		{
			return getProperty(BasicProperties.DIFFUSE_TRANSFORM);
		}
		public function set diffuseTransform(value : Matrix4x4) : void
		{
			setProperty(BasicProperties.DIFFUSE_TRANSFORM, value);
		}

        public function get uvOffset() : Vector4
        {
            return getProperty(BasicProperties.UV_OFFSET);
        }
        public function set uvOffset(value : Vector4) : void
        {
            setProperty(BasicProperties.UV_OFFSET, value);
        }

        public function get uvScale() : Vector4
        {
            return getProperty(BasicProperties.UV_SCALE);
        }
        public function set uvScale(value : Vector4) : void
        {
            setProperty(BasicProperties.UV_SCALE, value);
        }

		public function BasicMaterial(properties : Object = null, effect : Effect = null, name : String = DEFAULT_NAME)
		{
			super(effect || DEFAULT_EFFECT, properties, name);
		}

		override public function clone() : IDataProvider
		{
			var mat : BasicMaterial	= new BasicMaterial(this, effect, name);

			return mat;
		}
	}
}

add property BasicMaterial.diffuseMapWrapping


////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package org.apache.flex.html
{
	import org.apache.flex.core.ITextModel;
	import org.apache.flex.core.UIBase;
    COMPILE::JS
    {
        import org.apache.flex.core.WrappedHTMLElement;
    }

    /**
     *  The TextArea class implements the basic control for
     *  multi-line text input.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
     */
	public class TextArea extends UIBase
	{
        /**
         *  Constructor.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function TextArea()
		{
			super();
		}

        /**
         *  @copy org.apache.flex.html.Label#text
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function get text():String
		{
			return ITextModel(model).text;
		}

        /**
         *  @private
         */
		public function set text(value:String):void
		{
			ITextModel(model).text = value;
		}

        /**
         *  @copy org.apache.flex.html.Label#html
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function get html():String
		{
			return ITextModel(model).html;
		}

        /**
         *  @private
         */
		public function set html(value:String):void
		{
			ITextModel(model).html = value;
		}

        /**
         * @flexjsignorecoercion org.apache.flex.core.WrappedHTMLElement
         */
        COMPILE::JS
        override protected function createElement():WrappedHTMLElement
        {
            element = document.createElement('textarea') as WrappedHTMLElement;
            positioner = element;
            positioner.style.position = 'relative';
            element.flexjs_wrapper = this;
            element.className = 'TextArea';
            typeNames = 'TextArea';

            return element;
        }
	}
}

////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package org.apache.flex.html
{
	import org.apache.flex.core.ITextModel;
	import org.apache.flex.core.UIBase;
    COMPILE::JS
    {
        import org.apache.flex.core.WrappedHTMLElement;
    }

    /**
     *  The TextArea class implements the basic control for
     *  multi-line text input.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
     */
	public class TextArea extends UIBase
	{
        /**
         *  Constructor.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function TextArea()
		{
			super();
		}

        /**
         *  @copy org.apache.flex.html.Label#text
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         *  @flexjsignorecoercion HTMLInputElement
         */
		public function get text():String
		{
            COMPILE::AS3
            {
                return ITextModel(model).text;
            }
            COMPILE::JS
            {
                return (element as HTMLInputElement).value;
            }
		}

        /**
         *  @private
         *  @flexjsignorecoercion HTMLInputElement
         */
		public function set text(value:String):void
		{
            COMPILE::AS3
            {
                ITextModel(model).text = value;
            }
            COMPILE::JS
            {
                (element as HTMLInputElement).value = value;
            }
		}

        /**
         *  @copy org.apache.flex.html.Label#html
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function get html():String
		{
			return ITextModel(model).html;
		}

        /**
         *  @private
         */
		public function set html(value:String):void
		{
			ITextModel(model).html = value;
		}

        /**
         * @flexjsignorecoercion org.apache.flex.core.WrappedHTMLElement
         */
        COMPILE::JS
        override protected function createElement():WrappedHTMLElement
        {
            element = document.createElement('textarea') as WrappedHTMLElement;
            positioner = element;
            positioner.style.position = 'relative';
            element.flexjs_wrapper = this;
            element.className = 'TextArea';
            typeNames = 'TextArea';

            return element;
        }
	}
}

fix textarea

fix textarea


/**
 * Created by newkrok on 08/04/16.
 */
package ageofai.map.view
{
	import ageofai.building.view.home.HomeView;
	import ageofai.map.constant.CMap;
    import ageofai.map.constant.CMapNodeType;
	import ageofai.map.model.MapNode;

	import common.mvc.view.base.ABaseView;

	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.geom.Matrix;

	public class MapView extends ABaseView
	{
		private var _baseBackground:Bitmap;

		private var _terrainHelper:TerrainHelper;

		public function MapView()
		{
			var testMap:Vector.<Vector.<MapNode>> = new <Vector.<MapNode>>[];

			for( var i:int = 0; i < CMap.ROW_COUNT; i++ )
			{
				testMap.push( new <MapNode>[] );

				for( var j:int = 0; j < CMap.COLUMN_COUNT; j++ )
				{
					testMap[ i ].push( new MapNode() );
				}
			}

			this.createLayers();

			this.createMap( testMap );

			this.createHome();
			this.createHome();
			this.createHome();
			this.createHome();
		}

		private function createHome():void
		{
			var home:HomeView = this.addChild( new HomeView() ) as HomeView;
			home.x = CMap.TILE_SIZE * Math.floor( Math.random() * CMap.COLUMN_COUNT );
			home.y = CMap.TILE_SIZE * Math.floor( Math.random() * CMap.ROW_COUNT );
		}

		private function createLayers():void
		{
			this._terrainLayer = new Sprite();
			this.addChild( this._terrainLayer );

			this._unitLayer = new Sprite();
			this.addChild( this._unitLayer );
		}

		public function createMap( mapMatrix:Vector.<Vector.<MapNode>> ):void
		{
			this._terrainHelper = new TerrainHelper();
			this._terrainHelper.createBaseTerrainBitmapDatas();

			var lineCount:int = mapMatrix.length;
			var colCount:int = mapMatrix[ 0 ].length;

			var backgroundBitmapData:BitmapData = new BitmapData( lineCount * 32, colCount * 32, false, 0 );
			backgroundBitmapData.lock();

			for( var i:int = 0; i < lineCount; i++ )
			{
				for( var j:int = 0; j < colCount; j++ )
				{
					this.drawTerrainToBitmapData( i, j, backgroundBitmapData, mapMatrix[i][j].type );
				}
			}

			backgroundBitmapData.unlock();
			this._baseBackground = new Bitmap( backgroundBitmapData );
			addChild( this._baseBackground );

			this._terrainHelper.dispose();
		}

		private function drawTerrainToBitmapData( col:uint, row:uint, backgroundBitmapData:BitmapData, type:int ):void
		{
			var positionMatrix:Matrix = new Matrix();
			positionMatrix.tx = col * CMap.TILE_SIZE;
			positionMatrix.ty = row * CMap.TILE_SIZE;

			backgroundBitmapData.draw( type == CMapNodeType.GRASS ? this._terrainHelper.terrainGrassUI : this._terrainHelper.terrainDarkGrassUI, positionMatrix );
		}
	}
}

/**
 * Created by newkrok on 08/04/16.
 */
package ageofai.map.view
{
	import ageofai.building.view.home.HomeView;
	import ageofai.map.constant.CMap;
    import ageofai.map.constant.CMapNodeType;
	import ageofai.map.model.MapNode;

	import common.mvc.view.base.ABaseView;

	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.geom.Matrix;

	public class MapView extends ABaseView
	{
		private var _terrainLayer:Sprite;
		private var _unitLayer:Sprite;

		private var _baseBackground:Bitmap;

		private var _terrainHelper:TerrainHelper;

		public function MapView()
		{
			var testMap:Vector.<Vector.<MapNode>> = new <Vector.<MapNode>>[];

			for( var i:int = 0; i < CMap.ROW_COUNT; i++ )
			{
				testMap.push( new <MapNode>[] );

				for( var j:int = 0; j < CMap.COLUMN_COUNT; j++ )
				{
					testMap[ i ].push( new MapNode( 1 ) );
				}
			}

			this.createLayers();

			this.createMap( testMap );

			this.createHome();
			this.createHome();
			this.createHome();
			this.createHome();
		}

		private function createHome():void
		{
			var home:HomeView = this.addChild( new HomeView() ) as HomeView;
			home.x = CMap.TILE_SIZE * Math.floor( Math.random() * CMap.COLUMN_COUNT );
			home.y = CMap.TILE_SIZE * Math.floor( Math.random() * CMap.ROW_COUNT );
		}

		private function createLayers():void
		{
			this._terrainLayer = new Sprite();
			this.addChild( this._terrainLayer );

			this._unitLayer = new Sprite();
			this.addChild( this._unitLayer );
		}

		public function createMap( mapMatrix:Vector.<Vector.<MapNode>> ):void
		{
			this._terrainHelper = new TerrainHelper();
			this._terrainHelper.createBaseTerrainBitmapDatas();

			var lineCount:int = mapMatrix.length;
			var colCount:int = mapMatrix[ 0 ].length;

			var backgroundBitmapData:BitmapData = new BitmapData( lineCount * 32, colCount * 32, false, 0 );
			backgroundBitmapData.lock();

			for( var i:int = 0; i < lineCount; i++ )
			{
				for( var j:int = 0; j < colCount; j++ )
				{
					this.drawTerrainToBitmapData( i, j, backgroundBitmapData, mapMatrix[i][j].type );
				}
			}

			backgroundBitmapData.unlock();
			this._baseBackground = new Bitmap( backgroundBitmapData );
			addChild( this._baseBackground );

			this._terrainHelper.dispose();
		}

		private function drawTerrainToBitmapData( col:uint, row:uint, backgroundBitmapData:BitmapData, type:int ):void
		{
			var positionMatrix:Matrix = new Matrix();
			positionMatrix.tx = col * CMap.TILE_SIZE;
			positionMatrix.ty = row * CMap.TILE_SIZE;

			backgroundBitmapData.draw( type == CMapNodeType.GRASS ? this._terrainHelper.terrainGrassUI : this._terrainHelper.terrainDarkGrassUI, positionMatrix );
		}
	}
}

Test Map generation fixed

Test Map generation fixed

Test Map generation fixed


package aerys.minko.scene.node
{
	import aerys.minko.ns.minko_scene;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.controller.IRebindableController;
	import aerys.minko.scene.data.TransformDataProvider;
	import aerys.minko.type.Signal;
	import aerys.minko.type.clone.CloneOptions;
	import aerys.minko.type.clone.ControllerCloneAction;
	import aerys.minko.type.math.Matrix4x4;

	import flash.utils.Dictionary;
	import flash.utils.getQualifiedClassName;

	use namespace minko_scene;

	/**
	 * The base class to extend in order to create new scene node types.
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public class AbstractSceneNode implements ISceneNode
	{

		private static var _id			: uint							= 0;

		private var _name				: String						= null;
		private var _root				: ISceneNode					= null;
		private var _parent				: Group							= null;

		private var _transformData		: TransformDataProvider			= new TransformDataProvider();
		private var _transform			: Matrix4x4						= new Matrix4x4();

		private var _privateControllers	: Vector.<AbstractController>	= new <AbstractController>[];
		private var _publicControllers	: Vector.<AbstractController>	= new <AbstractController>[];

		private var _added				: Signal						= new Signal('AbstractSceneNode.added');
		private var _removed			: Signal						= new Signal('AbstractSceneNode.removed');
		private var _addedToScene		: Signal						= new Signal('AbstractSceneNode.addedToScene');
		private var _removedFromScene	: Signal						= new Signal('AbstractSceneNode.removedFromScene');
		private var _controllerAdded	: Signal						= new Signal('AbstractSceneNode.controllerAdded');
		private var _controllerRemoved	: Signal						= new Signal('AbstractSceneNode.controllerRemoved');

		public function get name() : String
		{
			return _name;
		}
		public function set name(value : String) : void
		{
			_name = value;
		}

		public function get parent() : Group
		{
			return _parent;
		}
		public function set parent(value : Group) : void
		{
			if (value == _parent)
				return ;

			// remove child
			if (_parent)
			{
				var oldParent : Group = _parent;

				oldParent._children.splice(
					oldParent.getChildIndex(this),
					1
				);

				parent._numChildren--;
				oldParent.descendantRemoved.execute(oldParent, this);

				_parent = null;
				_removed.execute(this, oldParent);
			}

			// set parent
			_parent = value;

			// add child
			if (_parent)
			{
				_parent._children[_parent.numChildren] = this;
				_parent._numChildren++;
				_parent.descendantAdded.execute(_parent, this);

				_added.execute(this, _parent);
			}
		}

		public function get root() : ISceneNode
		{
			return _root;
		}

		public function get transform() : Matrix4x4
		{
			return _transform;
		}

		public function get localToWorld() : Matrix4x4
		{
			return _transformData.localToWorld;
		}

		public function get worldToLocal() : Matrix4x4
		{
			return _transformData.worldToLocal;
		}

		public function get added() : Signal
		{
			return _added;
		}

		public function get removed() : Signal
		{
			return _removed;
		}

		public function get addedToScene() : Signal
		{
			return _addedToScene;
		}

		public function get removedFromScene() : Signal
		{
			return _removedFromScene;
		}

		public function get numControllers() : uint
		{
			return _publicControllers.length;
		}

		public function get controllerAdded() : Signal
		{
			return _controllerAdded;
		}

		public function get controllerRemoved() : Signal
		{
			return _controllerRemoved;
		}

		protected function get transformData() : TransformDataProvider
		{
			return _transformData;
		}

		public function AbstractSceneNode()
		{
			initialize();
		}

		private function initialize() : void
		{
			_name = getDefaultSceneName(this);
			_root = this;

			_added.add(addedHandler);
			_removed.add(removedHandler);
			_addedToScene.add(addedToSceneHandler);
			_removedFromScene.add(removedFromSceneHandler);

			_transform.changed.add(transformChangedHandler);
		}

		protected function addedHandler(child : ISceneNode, parent : Group) : void
		{
			_root = _parent ? _parent.root : this;
			if (_root is Scene)
				_addedToScene.execute(this, _root);

			if (child === this)
			{
				_parent.localToWorld.changed.add(transformChangedHandler);
				transformChangedHandler(_parent.transform);
			}
		}

		protected function removedHandler(child : ISceneNode, parent : Group) : void
		{
			// update root
			var oldRoot : ISceneNode = _root;

			_root = _parent ? _parent.root : this;
			if (oldRoot is Scene)
				_removedFromScene.execute(this, oldRoot);

			if (child === this)
				parent.localToWorld.changed.remove(transformChangedHandler);
		}

		protected function addedToSceneHandler(child : ISceneNode, scene : Scene) : void
		{
			// nothing
		}

		protected function removedFromSceneHandler(child : ISceneNode, scene : Scene) : void
		{
			// nothing
		}

		protected function transformChangedHandler(transform	: Matrix4x4) : void
		{
			if (_parent)
			{
				localToWorld.lock()
					.copyFrom(_transform)
					.append(_parent.localToWorld)
					.unlock();
			}
			else
				localToWorld.copyFrom(_transform);

			worldToLocal.lock()
				.copyFrom(localToWorld)
				.invert()
				.unlock();
		}

		public function addController(controller : AbstractController) : ISceneNode
		{
			_publicControllers.push(controller);

			controller.addTarget(this);
			_controllerAdded.execute(this, controller);

			return this;
		}

		public function removeController(controller : AbstractController) : ISceneNode
		{
			var numControllers	: uint = _publicControllers.length - 1;

			_publicControllers[_publicControllers.indexOf(controller)] = _publicControllers[numControllers];
			_publicControllers.length = numControllers;

			controller.removeTarget(this);
			_controllerRemoved.execute(this, controller);

			return this;
		}

		public function removeAllControllers() : ISceneNode
		{
			while (numControllers)
				removeController(getController(0));

			return this;
		}

		public function getController(index : uint) : AbstractController
		{
			return _publicControllers[index];
		}

		public function getControllersByType(type			: Class,
											 controllers	: Vector.<AbstractController> = null) : Vector.<AbstractController>
		{
			controllers ||= new Vector.<AbstractController>();

			var nbControllers : uint = numControllers;

			for (var i : int = 0; i < nbControllers; ++i)
			{
				var ctrl 	: AbstractController	= getController(i);

				if (ctrl is type)
					controllers.push(ctrl);
			}

			return controllers;
		}

		public static function getDefaultSceneName(scene : ISceneNode) : String
		{
			var className : String = getQualifiedClassName(scene);

			return className.substr(className.lastIndexOf(':') + 1)
				   + '_' + (++_id);
		}

		minko_scene function cloneNode() : AbstractSceneNode
		{
			throw new Error('Must be overriden');
		}

		public final function clone(cloneOptions : CloneOptions = null) : ISceneNode
		{
			cloneOptions ||= CloneOptions.defaultOptions;

			// fill up 2 dics with all nodes and controllers
			var nodeMap			: Dictionary = new Dictionary();
			var controllerMap	: Dictionary = new Dictionary();
			listItems(cloneNode(), nodeMap, controllerMap);

			// clone controllers with respect with instructions
			cloneControllers(controllerMap, cloneOptions);

			// rebind all controller dependencies.
			rebindControllerDependencies(controllerMap, nodeMap, cloneOptions);

			// add cloned/rebinded/original controllers to clones
			for (var objNode : Object in nodeMap)
			{
				var node			: AbstractSceneNode = AbstractSceneNode(objNode);
				var numControllers	: uint = node.numControllers;

				for (var controllerId : uint = 0; controllerId < numControllers; ++controllerId)
				{
					var controller : AbstractController = controllerMap[node.getController(controllerId)];
					if (controller != null)
						nodeMap[node].addController(controller);
				}
			}

			return nodeMap[this];
		}

		private function listItems(clonedRoot	: ISceneNode,
								   nodes		: Dictionary,
								   controllers	: Dictionary) : void
		{
			var numControllers : uint = this.numControllers;
			for (var controllerId : uint = 0; controllerId < numControllers; ++controllerId)
				controllers[getController(controllerId)] = true;

			nodes[this] = clonedRoot;

			if (this is Group)
			{
				var group		: Group = Group(this);
				var clonedGroup	: Group = Group(clonedRoot);
				var numChildren	: uint	= group.numChildren;

				for (var childId : uint = 0; childId < numChildren; ++childId)
				{
					var child		: AbstractSceneNode = AbstractSceneNode(group.getChildAt(childId));
					var clonedChild	: AbstractSceneNode = AbstractSceneNode(clonedGroup.getChildAt(childId));

					child.listItems(clonedChild, nodes, controllers);
				}
			}
		}

		private function cloneControllers(controllerMap : Dictionary, cloneOptions : CloneOptions) : void
		{
			for (var objController : Object in controllerMap)
			{
				var controller	: AbstractController = AbstractController(objController);
				var action		: uint				 = cloneOptions.getActionForController(controller);

				if (action == ControllerCloneAction.CLONE)
					controllerMap[controller] = controller.clone();
				else if (action == ControllerCloneAction.REASSIGN)
					controllerMap[controller] = controller;
				else if (action == ControllerCloneAction.IGNORE)
					controllerMap[controller] = null;
			}
		}

		private function rebindControllerDependencies(controllerMap	: Dictionary,
													  nodeMap		: Dictionary,
													  cloneOptions	: CloneOptions) : void
		{
			for (var objController : Object in controllerMap)
			{
				var controller	: AbstractController	= AbstractController(objController);
				var action		: uint					= cloneOptions.getActionForController(controller);

				if (controller is IRebindableController && action == ControllerCloneAction.CLONE)
					IRebindableController(controllerMap[controller]).rebindDependencies(nodeMap, controllerMap);
			}
		}
	}
}

package aerys.minko.scene.node
{
	import aerys.minko.ns.minko_scene;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.controller.IRebindableController;
	import aerys.minko.scene.data.TransformDataProvider;
	import aerys.minko.type.Signal;
	import aerys.minko.type.clone.CloneOptions;
	import aerys.minko.type.clone.ControllerCloneAction;
	import aerys.minko.type.math.Matrix4x4;

	import flash.utils.Dictionary;
	import flash.utils.getQualifiedClassName;

	use namespace minko_scene;

	/**
	 * The base class to extend in order to create new scene node types.
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public class AbstractSceneNode implements ISceneNode
	{

		private static var _id			: uint							= 0;

		private var _name				: String						= null;
		private var _root				: ISceneNode					= null;
		private var _parent				: Group							= null;

		private var _transformData		: TransformDataProvider			= new TransformDataProvider();
		private var _transform			: Matrix4x4						= new Matrix4x4();

		private var _controllers		: Vector.<AbstractController>	= new <AbstractController>[];

		private var _added				: Signal						= new Signal('AbstractSceneNode.added');
		private var _removed			: Signal						= new Signal('AbstractSceneNode.removed');
		private var _addedToScene		: Signal						= new Signal('AbstractSceneNode.addedToScene');
		private var _removedFromScene	: Signal						= new Signal('AbstractSceneNode.removedFromScene');
		private var _controllerAdded	: Signal						= new Signal('AbstractSceneNode.controllerAdded');
		private var _controllerRemoved	: Signal						= new Signal('AbstractSceneNode.controllerRemoved');

		public function get name() : String
		{
			return _name;
		}
		public function set name(value : String) : void
		{
			_name = value;
		}

		public function get parent() : Group
		{
			return _parent;
		}
		public function set parent(value : Group) : void
		{
			if (value == _parent)
				return ;

			// remove child
			if (_parent)
			{
				var oldParent : Group = _parent;

				oldParent._children.splice(
					oldParent.getChildIndex(this),
					1
				);

				parent._numChildren--;
				oldParent.descendantRemoved.execute(oldParent, this);

				_parent = null;
				_removed.execute(this, oldParent);
			}

			// set parent
			_parent = value;

			// add child
			if (_parent)
			{
				_parent._children[_parent.numChildren] = this;
				_parent._numChildren++;
				_parent.descendantAdded.execute(_parent, this);

				_added.execute(this, _parent);
			}
		}

		public function get root() : ISceneNode
		{
			return _root;
		}

		public function get transform() : Matrix4x4
		{
			return _transform;
		}

		public function get localToWorld() : Matrix4x4
		{
			return _transformData.localToWorld;
		}

		public function get worldToLocal() : Matrix4x4
		{
			return _transformData.worldToLocal;
		}

		public function get added() : Signal
		{
			return _added;
		}

		public function get removed() : Signal
		{
			return _removed;
		}

		public function get addedToScene() : Signal
		{
			return _addedToScene;
		}

		public function get removedFromScene() : Signal
		{
			return _removedFromScene;
		}

		public function get numControllers() : uint
		{
			return _controllers.length;
		}

		public function get controllerAdded() : Signal
		{
			return _controllerAdded;
		}

		public function get controllerRemoved() : Signal
		{
			return _controllerRemoved;
		}

		protected function get transformData() : TransformDataProvider
		{
			return _transformData;
		}

		public function AbstractSceneNode()
		{
			initialize();
		}

		private function initialize() : void
		{
			_name = getDefaultSceneName(this);
			_root = this;

			_added.add(addedHandler);
			_removed.add(removedHandler);
			_addedToScene.add(addedToSceneHandler);
			_removedFromScene.add(removedFromSceneHandler);

			_transform.changed.add(transformChangedHandler);
		}

		protected function addedHandler(child : ISceneNode, parent : Group) : void
		{
			_root = _parent ? _parent.root : this;
			if (_root is Scene)
				_addedToScene.execute(this, _root);

			if (child === this)
			{
				_parent.localToWorld.changed.add(transformChangedHandler);
				transformChangedHandler(_parent.transform);
			}
		}

		protected function removedHandler(child : ISceneNode, parent : Group) : void
		{
			// update root
			var oldRoot : ISceneNode = _root;

			_root = _parent ? _parent.root : this;
			if (oldRoot is Scene)
				_removedFromScene.execute(this, oldRoot);

			if (child === this)
				parent.localToWorld.changed.remove(transformChangedHandler);
		}

		protected function addedToSceneHandler(child : ISceneNode, scene : Scene) : void
		{
			// nothing
		}

		protected function removedFromSceneHandler(child : ISceneNode, scene : Scene) : void
		{
			// nothing
		}

		protected function transformChangedHandler(transform	: Matrix4x4) : void
		{
			if (_parent)
			{
				localToWorld.lock()
					.copyFrom(_transform)
					.append(_parent.localToWorld)
					.unlock();
			}
			else
				localToWorld.copyFrom(_transform);

			worldToLocal.lock()
				.copyFrom(localToWorld)
				.invert()
				.unlock();
		}

		public function addController(controller : AbstractController) : ISceneNode
		{
			_controllers.push(controller);

			controller.addTarget(this);
			_controllerAdded.execute(this, controller);

			return this;
		}

		public function removeController(controller : AbstractController) : ISceneNode
		{
			var numControllers	: uint = _controllers.length - 1;

			_controllers[_controllers.indexOf(controller)] = _controllers[numControllers];
			_controllers.length = numControllers;

			controller.removeTarget(this);
			_controllerRemoved.execute(this, controller);

			return this;
		}

		public function removeAllControllers() : ISceneNode
		{
			while (numControllers)
				removeController(getController(0));

			return this;
		}

		public function getController(index : uint) : AbstractController
		{
			return _controllers[index];
		}

		public function getControllersByType(type			: Class,
											 controllers	: Vector.<AbstractController> = null) : Vector.<AbstractController>
		{
			controllers ||= new Vector.<AbstractController>();

			var nbControllers : uint = numControllers;

			for (var i : int = 0; i < nbControllers; ++i)
			{
				var ctrl 	: AbstractController	= getController(i);

				if (ctrl is type)
					controllers.push(ctrl);
			}

			return controllers;
		}

		public static function getDefaultSceneName(scene : ISceneNode) : String
		{
			var className : String = getQualifiedClassName(scene);

			return className.substr(className.lastIndexOf(':') + 1)
				   + '_' + (++_id);
		}

		minko_scene function cloneNode() : AbstractSceneNode
		{
			throw new Error('Must be overriden');
		}

		public final function clone(cloneOptions : CloneOptions = null) : ISceneNode
		{
			cloneOptions ||= CloneOptions.defaultOptions;

			// fill up 2 dics with all nodes and controllers
			var nodeMap			: Dictionary = new Dictionary();
			var controllerMap	: Dictionary = new Dictionary();
			listItems(cloneNode(), nodeMap, controllerMap);

			// clone controllers with respect with instructions
			cloneControllers(controllerMap, cloneOptions);

			// rebind all controller dependencies.
			rebindControllerDependencies(controllerMap, nodeMap, cloneOptions);

			// add cloned/rebinded/original controllers to clones
			for (var objNode : Object in nodeMap)
			{
				var node			: AbstractSceneNode = AbstractSceneNode(objNode);
				var numControllers	: uint = node.numControllers;

				for (var controllerId : uint = 0; controllerId < numControllers; ++controllerId)
				{
					var controller : AbstractController = controllerMap[node.getController(controllerId)];
					if (controller != null)
						nodeMap[node].addController(controller);
				}
			}

			return nodeMap[this];
		}

		private function listItems(clonedRoot	: ISceneNode,
								   nodes		: Dictionary,
								   controllers	: Dictionary) : void
		{
			var numControllers : uint = this.numControllers;
			for (var controllerId : uint = 0; controllerId < numControllers; ++controllerId)
				controllers[getController(controllerId)] = true;

			nodes[this] = clonedRoot;

			if (this is Group)
			{
				var group		: Group = Group(this);
				var clonedGroup	: Group = Group(clonedRoot);
				var numChildren	: uint	= group.numChildren;

				for (var childId : uint = 0; childId < numChildren; ++childId)
				{
					var child		: AbstractSceneNode = AbstractSceneNode(group.getChildAt(childId));
					var clonedChild	: AbstractSceneNode = AbstractSceneNode(clonedGroup.getChildAt(childId));

					child.listItems(clonedChild, nodes, controllers);
				}
			}
		}

		private function cloneControllers(controllerMap : Dictionary, cloneOptions : CloneOptions) : void
		{
			for (var objController : Object in controllerMap)
			{
				var controller	: AbstractController = AbstractController(objController);
				var action		: uint				 = cloneOptions.getActionForController(controller);

				if (action == ControllerCloneAction.CLONE)
					controllerMap[controller] = controller.clone();
				else if (action == ControllerCloneAction.REASSIGN)
					controllerMap[controller] = controller;
				else if (action == ControllerCloneAction.IGNORE)
					controllerMap[controller] = null;
			}
		}

		private function rebindControllerDependencies(controllerMap	: Dictionary,
													  nodeMap		: Dictionary,
													  cloneOptions	: CloneOptions) : void
		{
			for (var objController : Object in controllerMap)
			{
				var controller	: AbstractController	= AbstractController(objController);
				var action		: uint					= cloneOptions.getActionForController(controller);

				if (controller is IRebindableController && action == ControllerCloneAction.CLONE)
					IRebindableController(controllerMap[controller]).rebindDependencies(nodeMap, controllerMap);
			}
		}
	}
}

Revert useless change on AbstractSceneNode


package
{
    import flash.display.Sprite;
    import flash.external.ExternalInterface;

    public class Impetus extends Sprite
    {
        private var sounds:Vector.<ImpetusSound>;

        public function Impetus():void
        {
            this.sounds = new Vector.<ImpetusSound>();

            if(ExternalInterface.available)
            {
                ExternalInterface.addCallback('getSound', this.getSound);
                ExternalInterface.addCallback('playNew', this.playNew);

                ExternalInterface.call("console.log", "Impetus loaded. (https://github.com/JWhile/Impetus)");
            }
        }

        public function getSound(url:String):ImpetusSound
        {
            var len:int = this.sounds.length;

            for(var i:int = 0; i < len; i++)
            {
                if(this.sounds[i].getUrl() === url)
                {
                    return this.sounds[i];
                }
            }

            var s:ImpetusSound = new ImpetusSound(url);

            this.sounds.push(s);

            return s;
        }

        public function playNew(url:String):void
        {
            this.getSound(url).playNew();
        }
    }
}

package
{
    import flash.display.Sprite;
    import flash.external.ExternalInterface;

    public class Impetus extends Sprite
    {
        private var sounds:Vector.<ImpetusSound>;

        public function Impetus():void
        {
            this.sounds = new Vector.<ImpetusSound>();

            if(ExternalInterface.available)
            {
                ExternalInterface.addCallback('playNew', this.playNew);

                ExternalInterface.call("console.log", "Impetus loaded. (https://github.com/JWhile/Impetus)");
            }
        }

        public function playNew(url:String):void
        {
            this.getSound(url).playNew();
        }

        private function getSound(url:String):ImpetusSound
        {
            var len:int = this.sounds.length;

            for(var i:int = 0; i < len; i++)
            {
                if(this.sounds[i].getUrl() === url)
                {
                    return this.sounds[i];
                }
            }

            var s:ImpetusSound = new ImpetusSound(url);

            this.sounds.push(s);

            return s;
        }
    }
}

Make getSound() private

Make getSound() private


package
{
    import flash.display.Sprite;
    import flash.external.ExternalInterface;

    public class Impetus extends Sprite
    {
        private var sounds:Vector.<ImpetusSound>;

        public function Impetus():void
        {
            this.sounds = new Vector.<ImpetusSound>();

            if(ExternalInterface.available)
            {
                ExternalInterface.addCallback('getSound', this.getSound);

                ExternalInterface.call("console.log", "Impetus loaded. (https://github.com/JWhile/Impetus)");
            }
        }

        public function getSound(url:String):ImpetusSound
        {
            var len:int = this.sounds.length;

            for(var i:int = 0; i < len; i++)
            {
                if(this.sounds[i].getUrl() === url)
                {
                    return this.sounds[i];
                }
            }

            var s:ImpetusSound = new ImpetusSound(url);

            this.sounds.push(s);

            return s;
        }
    }
}

package
{
    import flash.display.Sprite;
    import flash.external.ExternalInterface;

    public class Impetus extends Sprite
    {
        private var sounds:Vector.<ImpetusSound>;

        public function Impetus():void
        {
            this.sounds = new Vector.<ImpetusSound>();

            if(ExternalInterface.available)
            {
                ExternalInterface.addCallback('getSound', this.getSound);
                ExternalInterface.addCallback('playNew', this.playNew);

                ExternalInterface.call("console.log", "Impetus loaded. (https://github.com/JWhile/Impetus)");
            }
        }

        public function getSound(url:String):ImpetusSound
        {
            var len:int = this.sounds.length;

            for(var i:int = 0; i < len; i++)
            {
                if(this.sounds[i].getUrl() === url)
                {
                    return this.sounds[i];
                }
            }

            var s:ImpetusSound = new ImpetusSound(url);

            this.sounds.push(s);

            return s;
        }

        public function playNew(url:String):void
        {
            this.getSound(url).playNew();
        }
    }
}

Add playNew method to Impetus & ExternalInterface callbacks


package goplayer
{
  public class ConfigurationParser
  {
    private const result : Configuration = new Configuration

    private var parameters : Object

    public function ConfigurationParser(parameters : Object)
    { this.parameters = parameters }

    public function execute() : void
    {
      // XXX: Clean up the host stuff.
      result.host = parameters.host || "staging.streamio.se"
      result.skinURL = parameters.skin
        || "http://" + result.host + "/swfs/goplayer-black-skin.swf"
      result.movieID = parameters.movie
      result.trackerID = parameters.tracker || "global"
      result.bitratePolicy = getBitratePolicy("bitrate", BitratePolicy.BEST)
      result.enableRTMP = getBoolean("enableRtmp", true)
      result.enableAutoplay = getBoolean("enableAutoplay", false)
      result.enableLooping = getBoolean("enableLooping", false)
      result.enableChrome = getBoolean("enableChrome", true)
      result.enableUpperPanel = getBoolean("enableUpperPanel", true)
    }

    public static function parse(parameters : Object) : Configuration
    {
      const parser : ConfigurationParser
        = new ConfigurationParser(parameters)

      parser.execute()

      return parser.result
    }

    // -----------------------------------------------------

    private function getBitratePolicy
      (name : String, fallback : BitratePolicy) : BitratePolicy
    {
      if (name in parameters)
        return $getBitratePolicy(name, parameters[name], fallback)
      else
        return fallback
    }

    private function $getBitratePolicy
      (name : String, value : String,
       fallback : BitratePolicy) : BitratePolicy
    {
      try
        { return $$getBitratePolicy(value) }
      catch (error : Error)
        {
          reportInvalidParameter(name, value, BITRATE_POLICY_VALUES)
          return fallback
        }

      throw new Error
    }

    private const BITRATE_POLICY_VALUES : Array =
      ["<number>kbps", "min", "max", "best"]

    private function $$getBitratePolicy(value : String) : BitratePolicy
    {
      if (value == "max")
        return BitratePolicy.MAX
      else if (value == "min")
        return BitratePolicy.MIN
      else if (value == "best")
        return BitratePolicy.BEST
      else if (Bitrate.parse(value))
        return BitratePolicy.specific(Bitrate.parse(value))
      else
        throw new Error
    }

    // -----------------------------------------------------

    private function getBoolean
      (name : String, fallback : Boolean) : Boolean
    {
      if (name in parameters)
        return $getBoolean(name, parameters[name], fallback)
      else
        return fallback
    }

    private function $getBoolean
      (name : String, value : String, fallback : Boolean) : Boolean
    {
      try
        { return $$getBoolean(value) }
      catch (error : Error)
        {
          reportInvalidParameter(name, value, ["true", "false"])
          return fallback
        }

      throw new Error
    }

    private function $$getBoolean(value : String) : Boolean
    {
      if (value == "true")
        return true
      else if (value == "false")
        return false
      else
        throw new Error
    }

    // -----------------------------------------------------

    private function reportInvalidParameter
      (name : String, value : String, validValues : Array) : void
    {
      debug("Error: Invalid parameter: “" + name + "=" + value + "”; " +
            getInvalidParameterHint(validValues) + ".")
    }

    private function getInvalidParameterHint(values : Array) : String
    { return $getInvalidParameterHint(getQuotedValues(values)) }

    private function $getInvalidParameterHint(values : Array) : String
    {
      return "please use " +
        "either " + values.slice(0, -1).join(", ") + " " +
        "or " + values[values.length - 1]
    }

    private function getQuotedValues(values : Array) : Array
    {
      var result : Array = []

      for each (var value : String in values)
        result.push("“" + value + "”")

      return result
    }
  }
}

package goplayer
{
  public class ConfigurationParser
  {
    private const result : Configuration = new Configuration

    private var parameters : Object

    public function ConfigurationParser(parameters : Object)
    { this.parameters = parameters }

    public function execute() : void
    {
      // XXX: Clean up the host stuff.
      result.host = parameters.host || "staging.streamio.se"
      result.skinURL = parameters.skin
      result.movieID = parameters.movie
      result.trackerID = parameters.tracker || "global"
      result.bitratePolicy = getBitratePolicy("bitrate", BitratePolicy.BEST)
      result.enableRTMP = getBoolean("enableRtmp", true)
      result.enableAutoplay = getBoolean("enableAutoplay", false)
      result.enableLooping = getBoolean("enableLooping", false)
      result.enableChrome = getBoolean("enableChrome", true)
      result.enableUpperPanel = getBoolean("enableUpperPanel", true)
    }

    public static function parse(parameters : Object) : Configuration
    {
      const parser : ConfigurationParser
        = new ConfigurationParser(parameters)

      parser.execute()

      return parser.result
    }

    // -----------------------------------------------------

    private function getBitratePolicy
      (name : String, fallback : BitratePolicy) : BitratePolicy
    {
      if (name in parameters)
        return $getBitratePolicy(name, parameters[name], fallback)
      else
        return fallback
    }

    private function $getBitratePolicy
      (name : String, value : String,
       fallback : BitratePolicy) : BitratePolicy
    {
      try
        { return $$getBitratePolicy(value) }
      catch (error : Error)
        {
          reportInvalidParameter(name, value, BITRATE_POLICY_VALUES)
          return fallback
        }

      throw new Error
    }

    private const BITRATE_POLICY_VALUES : Array =
      ["<number>kbps", "min", "max", "best"]

    private function $$getBitratePolicy(value : String) : BitratePolicy
    {
      if (value == "max")
        return BitratePolicy.MAX
      else if (value == "min")
        return BitratePolicy.MIN
      else if (value == "best")
        return BitratePolicy.BEST
      else if (Bitrate.parse(value))
        return BitratePolicy.specific(Bitrate.parse(value))
      else
        throw new Error
    }

    // -----------------------------------------------------

    private function getBoolean
      (name : String, fallback : Boolean) : Boolean
    {
      if (name in parameters)
        return $getBoolean(name, parameters[name], fallback)
      else
        return fallback
    }

    private function $getBoolean
      (name : String, value : String, fallback : Boolean) : Boolean
    {
      try
        { return $$getBoolean(value) }
      catch (error : Error)
        {
          reportInvalidParameter(name, value, ["true", "false"])
          return fallback
        }

      throw new Error
    }

    private function $$getBoolean(value : String) : Boolean
    {
      if (value == "true")
        return true
      else if (value == "false")
        return false
      else
        throw new Error
    }

    // -----------------------------------------------------

    private function reportInvalidParameter
      (name : String, value : String, validValues : Array) : void
    {
      debug("Error: Invalid parameter: “" + name + "=" + value + "”; " +
            getInvalidParameterHint(validValues) + ".")
    }

    private function getInvalidParameterHint(values : Array) : String
    { return $getInvalidParameterHint(getQuotedValues(values)) }

    private function $getInvalidParameterHint(values : Array) : String
    {
      return "please use " +
        "either " + values.slice(0, -1).join(", ") + " " +
        "or " + values[values.length - 1]
    }

    private function getQuotedValues(values : Array) : Array
    {
      var result : Array = []

      for each (var value : String in values)
        result.push("“" + value + "”")

      return result
    }
  }
}

Remove hard-coded default skinURL.

Remove hard-coded default skinURL.