ExternalInterface evaluate given JavaScript string (anonymous functions): ExternalInterface.call("(function(param1, param2) {/* javascript code here */})", parameter1, parameter2);
Note: don’t use the dash character "-" or other special chars in the DOM id of your flash element. IE need id attribute for using ExtenralInterface, others need name attribute.
IE native JavaScript function for hanlding Flash & JS exchanges
function __flash__arrayToXML(obj)
{
var s = "<array>";
for (var i=0; i<obj.length; i++)
s += "<property id=\"" + i + "\">" + __flash__toXML(obj[i]) + "</property>";
return s+"</array>";
}
function __flash__argumentsToXML(obj, index)
{
var s = "<arguments>";
for (var i=index; i<obj.length; i++)
s += __flash__toXML(obj[i]);
return s+"</arguments>";
}
function __flash__objectToXML(obj)
{
var s = "<object>";
for (var prop in obj)
s += "<property id=\"" + prop + "\">" + __flash__toXML(obj[prop]) + "</property>";
return s+"</object>";
}
function __flash__escapeXML(s)
{
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
}
function __flash__toXML(value)
{
var type = typeof(value);
if (type == "string")
return "<string>" + __flash__escapeXML(value) + "</string>";
else if (type == "undefined")
return "<undefined/>";
else if (type == "number")
return "<number>" + value + "</number>";
else if (value == null)
return "<null/>";
else if (type == "boolean")
return value ? "<true/>" : "<false/>";
else if (value instanceof Date)
return "<date>" + value.getTime() + "</date>";
else if (value instanceof Array)
return __flash__arrayToXML(value);
else if (type == "object")
return __flash__objectToXML(value);
else
return "<null/>"; //???
}
function __flash__addCallback(instance, name)
{
instance[name] = function()
{
return eval(instance.CallFunction("<invoke name=\""+name+"\" returntype=\"javascript\">" + __flash__argumentsToXML(arguments,0) + "</invoke>"));
}
}
function __flash__removeCallback(instance, name)
{
instance[name] = null;
}
package foo
{
[RemoteClass(alias="foo.Bar")]
public class Bar
{
// public field
public var prop1:String;
// private field but keeped
[Transient]
private var prop2:Array;
}
}
Applied in all places using AMF encoding (RemoteObject, NetConnection, byteArray.readObject();)
See flash.net.registerClassAlias()
Use AS3 metadata
-keep-as3-metadata+=Meta1,Meta2
package
{
[Meta2(param1 = "param 1 value")]
public class TestClass
{
[Meta1(param1 = "param 1 value", param2 = "param 2 value")]
public var test1:String;
[Meta2(paramA = "param 1 value", paramB = "param 2 value")]
public function get test2():String
{
return null;
}
public function set test2(val:String):void
{
}
[Meta1(param1 = "param 1 value")]
public function someMethod():void
{
}
}
}
var classMetadatas:XMLList = describeType(TestClass).factory.metadata;
var methodsMetadatas:XMLList = describeType(TestClass).factory.method.metadata;
var variablesMetadatas:XMLList = describeType(TestClass).factory.variable.metadata;
var accessorsMetadatas:XMLList = describeType(TestClass).factory.accessor.metadata;
StreamClient(){
onCuePoint(infos:Object):void
onImageData(infos:Object):void
onLastSecond(infos:Object):void
onMetaData(infos:Object):void
onPlayStatus(infos:Object):void
onTextData(infos:Object):void
onXMPData(infos:Object):void
}
// Dynamic Buffering
// From http://sonnati.wordpress.com/2006/04/10/dynamic-buffering-revamping/ http://sonnati.wordpress.com/2005/12/03/241/
// Init
startBL = 2;
mainBL = 15;
in_ns.setBufferTime(startBL);
in_ns.onStatus = function statusHandler(infoObject:Object) {
if (infoObject["code"] == "NetStream.Buffer.Full"){
in_ns.setBufferTime(mainBL);
}
if (infoObject["code"] == "NetStream.Buffer.Empty"){
in_ns.setBufferTime(startBL);
}
}
// Load video bytes
// http://www.bytearray.org/?p=1689
// retrieve the FLV stream
var bytes:ByteArray = event.currentTarget.data;
// put the NetStream class into Data Generation mode
netstream.play(null);
// before appending new bytes, reset the position to the beginning
netstream.appendBytesAction(NetStreamAppendBytesAction.RESET_BEGIN);
// append the FLV video bytes
netstream.appendBytes(bytes);
// HTTP Dynamic stream/HTTP Streaming
public class MiniStream extends Sprite
{
private var _buffer:ByteArray = new ByteArray();
private var _ns:NetStream;
private var _nc:NetConnection;
private var _video:Video;
private var _tc:Number = 0;
private var _ustream:URLStream;
private var _elapsed_bytes:uint = 0;
public function MiniStream(onVideo:Function)
{
_video = new Video(400,300);
addChild(_video);
_ustream = new URLStream();
_ustream.addEventListener(IOErrorEvent.IO_ERROR, onErr);
_ustream.addEventListener(ProgressEvent.PROGRESS, onProgress);
}
public function play():void
{
_nc = new NetConnection();
_nc.connect(null);
if(_ns)
{
_ns.removeEventListener(NetStatusEvent.NET_STATUS, onStatus);
}
_ns = new NetStream(_nc);
_ns.addEventListener(NetStatusEvent.NET_STATUS, onStatus);
_ns.client = {};
_ns.bufferTime = 3;
_video.attachNetStream(_ns);
_ns.play(null);
_ns.appendBytesAction(NetStreamAppendBytesAction.RESET_BEGIN);
_ustream.load("http://example.com/h264vid.flv");
}
private function onStatus(e:NetStatusEvent):void
{
trace(e.info.code);
}
private function onProgress(e:ProgressEvent):void
{
//stores in our BA buffer
_ustream.readBytes(_buffer,0,_ustream.bytesAvailable);
_buffer.position = 0;
if(_buffer.bytesAvailable > 0)
{
_ns.appendBytes(_buffer);
_elapsed_bytes += _buffer.length;
_buffer.clear();
}
}
private function onErr(e:IOErrorEvent):void
{
//trace("ERROR", e.text);
}
}
var displayObject:DisplayObject;
var bounds:Rectangle = displayObject.getBounds(displayObject);
var bitmapData:BitmapData = new BitmapData(uint(bounds.width + 0.5), uint(bounds.height + 0.5), true, 0);
bitmapData.draw(displayObject, new Matrix(1, 0, 0, 1, -bounds.x, -bounds.y));
Pixelize a DisplayObject
Draw it into a BitmapData (see above) with scale
var displayObject:DisplayObject;
var scale:Number = 0.5;
var bounds:Rectangle = displayObject.getBounds(displayObject);
var bitmapData:BitmapData = new BitmapData(uint((bounds.width + 0.5) * scale), uint((bounds.height + 0.5) * scale), true, 0);
bitmapData.draw(displayObject, new Matrix(scale, 0, 0, scale, -bounds.x * scale, -bounds.y * scale));
Then, set bitmap width & height to original sizes (bounds.width & bounds.height)
NetStream BitmapData capture
video.attachNetStream(null);
var snapshot:BitmapData = new BitmapData(…);
snapshot.draw(video);
video.attachNetStream(stream);
Outlined Text
new GlowFilter(0x000000, 1.0, 2.0, 2.0, 10, 2)
Network & File IO
Upload file with URLLoader
/**
* Original:
* http://www.jooce.com/blog/?p=143
* Uploads a file using a given URLLoader object.
*
* @param loader The URLLoader object to use
* @param url The location of the script recieving the upload
* @param file The file to upload
* @param fileName The name of the file
* @param contentType The content-type of the file
*/
var loader:URLLoader = new URLLoader();
var file:ByteArray = new ByteArray();
file.writeUTFBytes("Fake file content text.");
var request:URLRequest = new URLRequest("my/path/upload.php");
var fileName:String = "myfile.txt";
var contentType:String = "text/plain";//"application/octet-stream"
var i:int;
var boundary:String = "--";
var postData:ByteArray = new ByteArray;
var bytes:String;
for(i = 0; i < 0x10; i++)
boundary += String.fromCharCode(int(97 + Math.random() * 25));
loader.dataFormat = URLLoaderDataFormat.BINARY;
request.url = url;
request.contentType = "multipart/form-data; boundary=" + boundary;
request.method = URLRequestMethod.POST;
postData.endian = Endian.BIG_ENDIAN;
// -- + boundary
postData.writeShort(0x2d2d);
for (i = 0; i < boundary.length; i++)
postData.writeByte(boundary.charCodeAt(i));
// line break
postData.writeShort(0x0d0a);
// content disposition
bytes = "Content-Disposition: form-data; name=\"Filename\"";
for (i = 0; i < bytes.length; i++)
postData.writeByte(bytes.charCodeAt(i));
// 2 line breaks
postData.writeInt(0x0d0a0d0a);
// file name
postData.writeUTFBytes(fileName);
// line break
postData.writeShort(0x0d0a);
// -- + boundary
postData.writeShort(0x2d2d);
for (i = 0; i < boundary.length; i++)
postData.writeByte(boundary.charCodeAt(i));
// line break
postData.writeShort(0x0d0a);
// content disposition
bytes = "Content-Disposition: form-data; name=\"Filedata\"; filename=\"";
for (i = 0; i < bytes.length; i++)
postData.writeByte(bytes.charCodeAt(i));
// file name
postData.writeUTFBytes(fileName);
// missing "
postData.writeByte(0x22);
// line break
postData.writeShort(0x0d0a);
// content type
bytes = "Content-Type: " + contentType;
for (i = 0; i < bytes.length; i++)
postData.writeByte(bytes.charCodeAt(i));
// 2 line breaks
postData.writeInt(0x0d0a0d0a);
// file data
postData.writeBytes(file, 0, file.length);
// line break
postData.writeShort(0x0d0a);
// -- + boundary
postData.writeShort(0x2d2d);
for (i = 0; i < boundary.length; i++)
postData.writeByte(boundary.charCodeAt(i));
// line break
postData.writeShort(0x0d0a);
// upload field
bytes = "Content-Disposition: form-data; name=\"Upload\"";
for (i = 0; i < bytes.length; i++)
postData.writeByte(bytes.charCodeAt(i));
// 2 line breaks
postData.writeInt(0x0d0a0d0a);
// submit
bytes = "Submit Query";
for (i = 0; i < bytes.length; i++)
postData.writeByte(bytes.charCodeAt(i));
// line break
postData.writeShort(0x0d0a);
// -- + boundary + --
postData.writeShort(0x2d2d);
for (i = 0; i < boundary.length; i++)
postData.writeByte(boundary.charCodeAt(i));
postData.writeShort(0x2d2d);
request.data = postData;
request.requestHeaders.push(new URLRequestHeader("Cache-Control", "no-cache"));
loader.load(request);
var array:Array = ["a", "b", "c"];
var vector:Vector.<String> = Vector.<String>(array);
Conditional switch statement
var value:int = 2;
switch(value){
case < 1:
trace("Value is less than 1");
break;
case 2:
trace("Value definitely equals 2");
break;
case >= 3:
trace("Value is greater than or equal to 3");
break;
case > 1 && < 3:
trace("Value is greater than 3 and less than 5");
break;
case !== 5:
trace("Value definitely doesn't equal 5");
break;
}
Compare real types of objects
With (final contructor) != is keyword
public static function typeEquals(object:*, constructor:Class):Boolean
{
return o == null ? false : Object(object).constructor == constructor;
}
Extends Array
And support Array's arguments
public class SubArray extends Array
{
function SubArray():void
{
super.constructor.apply(this, arguments);
}
}
if(!instantiationAllowed)
// %1 class cannot be instantiated.
Error.throwError(IllegalOperationError, 2012, "MyClass");
Desactivate constructor super call
if (0)
super();
Estimate sound duration while loading
var duration:Number = this.sound.length;
if (this.sound.bytesTotal != this.sound.bytesLoaded && duration > 0)
duration = (this.sound.bytesTotal / (this.sound.bytesLoaded / duration));
Forcing Garbage collecting
try
{
new LocalConnection().connect('foo');
new LocalConnection().connect('foo');//The GC will perform a full mark/sweep on the second call.
} catch (error:*) {}
LocalConnection limits
LocalConnection.send() limited to 40960 bytes. For one ByteArray is limited to 40864 (+ AMF data for one ByteArray: 96 bytes ?)
Throw error
Error.throwError(RangeError, 1005 /*kArrayIndexNotIntegerError*/, -3);//throw Error #1005: Array index is not an integer (-3)
Error.throwError(type:Class, errorID:uint, ...rest);
Product("digitaleditions2x0")
//AS2
var p = new System.Product("notepad");
p.download();
trace(p.IsInstalled());
trace(p.Launch());
And you copy "notepad.exe" to
// ApplicationData\Macromedia\FlashPlayer\www.macromedia.com\bin\notepad\
//AS3
var p:ProductManager = new adobe.utils.ProductManager()
p.launch();
p.download();
p.installed;
p.installedVersion;
p.running;
//AS3 launch AIR app
myLauncher:ProductManager = new ProductManager("airappinstaller");
var myArguments:Array = ["-launch", appID, publisherID, theOtherAppArguments];
myLauncher.launch(myArguments.join(" "));
fpupdateax
digitaleditions2x0
airappinstaller
fpupdatepl
Access to all members (inc. private) of a specified object (debug player only)
import flash.sampler.getMemberNames;
//…
var members:Object = getMemberNames(myObject);
for each (var name:QName in members)
if (name.localName == "memberName")
trace(myObject[name]);
Get class from Loaded SWF
loader.contentLoaderInfo.applicationDomain.getDefinition("FullQualifiedClassName") as Class
Clone object
Not work on DisplayObjects
package nc.utils
{
import flash.utils.ByteArray;
import flash.net.registerClassAlias;
import flash.utils.getQualifiedClassName;
import flash.net.getClassByAlias;
import flash.utils.describeType;
import flash.utils.getDefinitionByName;
public class ObjectUtils
{
/**
* Clone an Object
*
* @param object The Object to clone (Object is not a part of the displayList
* and object don't need arguments in constructor)
*
* @param type The Class of the Object to clone.
*
* @return a clone of Object
*/
public static function clone(object:*):*
{
var alias:String = getQualifiedClassName(object).split('::').join('.');
var type:Class = getDefinitionByName(alias) as Class;
traverse(object);
var r:ByteArray = new ByteArray();
r.writeObject(object);
r.position = 0;
var clone:*;
try
{
clone = r.readObject();
return clone as type;
}
catch(error:TypeError)
{
//trace(error);
}
return null;
}
private static function traverse(object:*):void
{
var alias : String = getQualifiedClassName(object).split('::').join('.');
var type : Class = getDefinitionByName(alias) as Class;
try
{
getClassByAlias(alias);
}
catch(error:ReferenceError)
{
registerClassAlias(alias, type);
}
var x:XML = describeType(object),
childrens:XMLList = x.children(),
l:int = childrens.length(),
i:int = -1,
xClass:XML;
while (++i<l)
{
xClass = childrens[i] as XML;
registerAll(xClass);
var childName:String = xClass.attribute("name");
if(xClass.name() == "variable")
{
var childObj:* = object[childName];
if(null != childObj)
traverse(childObj);
}
}
}
private static function registerAll(x:XML):void
{
var a : Array = ['type','declaredBy','returnType'],
l : int = a.length,
i : int = -1,
raw : String,
aSplit : Array,
type : Class,
alias : String;
while (++i<l)
{
raw = x.attribute(a[i] as String).toString();
if (raw.indexOf('::') != -1)
{
aSplit = raw.split('::');
if (aSplit.length == 2)
{
alias = aSplit.join('.');
type = getDefinitionByName(alias) as Class;
try
{
getClassByAlias(alias)
}
catch(error:ReferenceError)
{
trace("Register --> " + alias + " as " + type);
registerClassAlias(alias, type);
}
}
}
}
}
}
}
#!/usr/local/bin/php
<?php
/**
* Flash Policy Service v0.9.c
*
* This script listens for <policy-file-request/> on port 843 and serves up
* an xml crossdomain policy file. This sort of service is necessary if any
* flash content is going to connect to sockets on the running host.
*
* I have made every effort to package everything you need into a single
* file here, even though it could easily have been split into 3 or more
* scripts.
*
* Requirements:
* - PHP 5 with sockets, pcntl, and posix extensions
* - Root access (to bind to a <1024 port)
*
* Use:
* Simply execute the script from the command line as root:
* # ./FlashPolicyService.php
* You can enable debug mode by invoking the script with '-d' as a parameter:
* # ./FlashPolicyService.php -d
* To stop the daemon, simply send it a SIGTERM and it should attempt to
* exit cleanly.
*
* If you get 'bad interpreter' errors or the like, change the #! line to
* reflect the actual installed location of your php cli.
*
* Configuration:
* At present, there aren't very many config options. Simply edit the
* section immediately following this header. Options are commented.
*
* License:
* This code is made available under a Creative Commons Attribution 3.0
* License. Basically, you can use it however you like, but I would
* appreciate some credit when you do.
*
* Disclaimer:
* I make no guarantees that this code won't make your server explode in a
* shower of blue flames. However, I don't expect that it will. I am actually
* confident that this code will be helpful.
*
* That said, this is still my beta release. If you find any bugs, please
* let me know so I can fix them.
*
* - Ammon Lauritzen [Apr 21, '08]
- http://ammonlauritzen.com/blog/2008/04/22/flash-policy-service-daemon/
*
* Changelog
* 0.9.c
- - Fixed some typoes that were the result of how I combined everything
* into a single file. Thanks Alex!
* 0.9.b
- - Original version to be posted at this url.
* 0.9.a
- - Original proof of concept code posted online.
*/
/*** Config ***/
// where should we save the log output?
$log_filename = "/tmp/flash-policy.log";
// uncomment these lines to choose which user to run the daemon as
// default behavior is to look up and attempt to run as 'nobody'
# $daemon_uid = 99;
# $daemon_gid = 99;
// set this if you want to use an external file in stead of the default
$xml_filename = "";
$default_xml =
'<'.'?xml version="1.0" encoding="UTF-8"?'.'>'.
'<cross-domain-policy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.adobe.com/xml/schemas/PolicyFileSocket.xsd">'.
'<allow-access-from domain="*" to-ports="*" secure="false" />'.
'<site-control permitted-cross-domain-policies="all" />'.
'</cross-domain-policy>';
/*** You shouldn't have to edit anything below here ***/
/////////////////////////////////////////////////////////////////////////////
class Logger {
public function __construct($logfile) {
$this->logfile = $logfile;
$this->open_log();
}// end: constructor
public function __destruct() {
@fflush($this->fh);
@fclose($this->fh);
}// end: destructor
public function log($msg) {
// deal with redundant log spam
if($msg == $this->last_msg) {
$this->last_msg_count++;
return;
} else if($this->last_msg_count) {
$this->write("Last message repeated ".$this->last_msg_count." times.");
}
$this->lasg_msg = $msg;
$this->last_msg_count = 0;
// actually write the log message out
$this->write($msg);
}// end: log
private function write($msg) {
$msg = sprintf("[%s] %s\n",date("y-m-d H:i:s"),$msg);
$succ = @fwrite($this->fh, $msg);
if($succ === FALSE) {
echo $msg;
}
}// end: write
private function open_log() {
if(!file_exists($this->logfile)) {
touch($this->logfile);
chmod($this->logfile, 0664);
}
$this->fh = @fopen($this->logfile, "a");
}
}// end: logger class
/////////////////////////////////////////////////////////////////////////////
class Daemon {
public function __construct() {
error_reporting(0);
set_time_limit(0);
global $log_filename, $pid_filename;
$this->logger = new Logger($log_filename);
$this->pid_filename = $pid_filename;
$this->log_tag = $this->daemon_tag = "launcher";
$this->debug("constructed", $this->daemon_tag);
}// end: constructor
public function __destruct() {
$this->debug("destructing", $this->daemon_tag);
}// end: destructor
protected function log($msg, $tag = false) {
if($tag == false)
$tag = $this->log_tag;
$this->logger->log($tag.": ".$msg);
}// end: log
protected function debug($msg, $tag = false) {
if(DEBUG)
$this->log($msg, $tag);
}// end: debug
protected function main() {
$this->log("override main() in daemon subclass", $this->daemon_tag);
$this->stop();
}// end: main
public function start() {
$this->log("starting daemon", $this->daemon_tag);
if(!$this->_start()) {
$this->log("unable to start daemon", $this->daemon_tag);
return;
}
// report execution details
$this->log("uid = ".posix_getuid().", gid = ".posix_getgid());
$this->log("cwd = ".getcwd());
// invoke main loop
$this->running = true;
while($this->running) {
$this->main();
}
}// end: start
private function _start() {
if(!$this->_fork()) {
return false;
}// end: try to fork
if(!posix_setsid()) {
$this->log("unable to setsid()", $this->daemon_tag);
return false;
}// end: try to set sid
if(!$this->_suid()) {
return false;
}// end: try to set uid
// register signal handler
declare(ticks = 1);
pcntl_signal(SIGTERM, array(&$this, "on_sigterm"));
// chdir somewhere moderately safe by default
chdir('/tmp');
return true;
}// end: _start
private function _fork() {
$this->log("forking…", $this->daemon_tag);
$pid = pcntl_fork();
if($pid == -1) {
// error
$this->log("unable to fork", $this->daemon_tag);
return false;
} else if($pid) {
// parent
$this->debug("done with parent", $this->daemon_tag);
exit(0);
} else {
// child
$this->daemon_tag = "daemon";
$this->child = true;
$this->pid = posix_getpid();
$this->debug("child pid = ".$this->pid);
return true;
}
}// end: _fork
private function _suid() {
global $daemon_uid, $daemon_gid;
if(!isset($daemon_uid) || !isset($daemon_gid)) {
// we didn't get a uid/gid, try to make one up
$this->debug("searching for info on 'nobody'", $this->daemon_tag);
$res = posix_getpwnam("nobody");
if($res !== FALSE) {
$uid = $res['uid'];
$gid = $res['gid'];
} else {
// the 'nobody' user doesn't exist on this system, refuse
// to daemonize as root
$this->log("unable to find info on 'nobody' user", $this->daemon_tag);
return false;
}
} else {
$this->debug("got uid/gid of $daemon_uid/$daemon_gid", $this->daemon_tag);
$uid = $daemon_uid;
$gid = $daemon_gid;
}
// actually try to switch now
if(!posix_setgid($gid)) {
$this->log("unable to set gid to ".$gid, $this->daemon_tag);
return false;
} else if(!posix_setuid($uid)) {
$this->log("unable to set uid to ".$uid, $this->daemon_tag);
return false;
} else {
return true;
}
}// end: _suid
public function stop() {
$this->log("stopping daemon", $this->daemon_tag);
$this->running = false;
}// end: stop
protected function on_sigterm($sig) {
if($sig == SIGTERM) {
$this->log("got SIGTERM", $this->daemon_tag);
$this->stop();
exit(0);
}
}// end: on_sigterm
}// end: daemon class
/////////////////////////////////////////////////////////////////////////////
class FlashPolicyService extends Daemon {
public function __construct() {
parent::__construct();
$this->log_tag = "fps";
$this->debug("constructing");
$this->connections = array();
$this->request_str = "<policy-file-request/>";
$this->port = 843;
// get our xml
global $xml_filename, $default_xml;
if(strlen($xml_filename) == 0 || !file_exists($xml_filename)) {
$this->log("unable to read xml from '$xml_filename', using default");
$this->xml = $default_xml;
} else {
$this->log("reading policy xml from $xml_filename");
$this->xml = file_get_contents($xml_filename);
}
$this->debug("policy xml: ".$this->xml);
// make sure we're null terminated
$this->xml = trim($this->xml)."\n\0";
// and get going
$this->init();
}// end: constructor
public function __destruct() {
parent::__destruct();
if($this->sock)
@fclose($this->sock);
}// end: destructor
private function init() {
$this->debug("init…");
if($this->check_socket()) {
parent::start();
} else {
$this->log("not starting daemon");
}
}// end: init
protected function main() {
if($this->sock) {
while(true) {
$this->accept_socket();
}
} else {
$this->log("server socket is closed?!");
parent::stop();
}
// paranoia to keep from absolutely hosing cpu if something goes wrong
usleep(10000); // 10ms
}// end: main
private function check_socket() {
$this->sock = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if(!$this->sock) {
$this->log("unable to create socket");
} else {
$succ = @socket_bind($this->sock, "0.0.0.0", $this->port);
if(!$succ) {
$this->log("unable to bind to port ".$this->port);
} else {
$backlog = 100;
$succ = @socket_listen($this->sock, $backlog);
if(!$succ) {
$this->log("unable to listen with backlog of $backlog");
} else {
// everything's good
return true;
}
}// end: able to bind
}// end: able to create socket
// if we got here, it's an error. abort.
$errno = socket_last_error($this->sock);
$errstr = socket_strerror($errno);
$this->log("socket error: $errno: $errstr");
return false;
}// end: check_socket
private function accept_socket() {
$r_socks = array_merge(array($this->sock), $this->connections);
$this->debug("selecting on ".count($r_socks)." sockets");
// block until something interesting happens
$select = @socket_select($r_socks, $w_socks = NULL, $e_socks = NULL, NULL);
if(!$select)
return;
// did we get a new connection?
if(in_array($this->sock, $r_socks)) {
$conn = @socket_accept($this->sock);
if($conn !== false)
@socket_getpeername($conn, $addr);
$this->log("connection accepted from $addr, $conn");
$this->connections[] = $conn;
}// end: got a new connection
// check for policy requests
foreach($r_socks as $conn) {
// ignore the server socket
if($conn == $this->sock)
continue;
// read from the client
$data = @socket_read($conn, 1024);
if($data === FALSE) {
$this->log("got disconnect from $conn");
}// end: client closed connection
else {
$this->debug("read '".trim($data)."' from $conn");
if(strpos($data, $this->request_str) !== FALSE) {
$this->log("sending policy xml to $conn");
@socket_write($conn, $this->xml);
} else {
$this->log("got invalid request from $conn");
}
}// end: got data from the client
// and always disconnect after having read something, whether
// it was a valid request or not - especially if it wasn't ;)
@socket_close($conn);
$key = array_search($conn, $this->connections);
if($key !== FALSE)
unset($this->connections[$key]);
}// end: foreach socket
}// end: accept_socket
}// end: flash policy service class
/////////////////////////////////////////////////////////////////////////////
/**
* Actual execution code here. This checks if the php install has all of our
* requisite extensions, makes sure we're launching as root, and checks if
* debug mode was requested before actually starting the daemon.
*/
// make sure we have required extensions
$required_extensions = array("sockets", "posix", "pcntl");
$missing_extension = false;
foreach($required_extensions as $ext) {
if(!extension_loaded($ext)) {
echo "Missing required php extension '$ext'.n";
$missing_extension = true;
}
}
if($missing_extension) {
exit(1);
}
// make sure we launch as root, otherwise we can't bind to 843
if(posix_getuid() != 0 || posix_getgid() != 0) {
echo "Policy service must be started as root.n";
exit(1);
}
// see if we're in debug mode
define("DEBUG", in_array('-d',$argv));
// start the daemon
$fps = new FlashPolicyService();
?>
#!/usr/bin/php -q
<?php
error_reporting(E_ALL);
set_time_limit(0);
ob_implicit_flush();
echo "Enter Server IP:\n";
$address = trim(fgets(STDIN));
//$address = '127.0.0.1';
echo "Enter Port:\n";
$port = trim(fgets(STDIN));
//$port = 9999;
echo "Attempting to connect to $address:$port\n";
//---- Function to Send out Messages to Everyone Connected ----------------------------------------
function send_Message($allclient, $buf) {
global $client_list;
foreach($allclient as $client) {
if($client_list[$client]['state'] && $client_list[$client]['nick'] != ""){
socket_write($client, trim($buf).chr(0));
}
}
}
function who($allclient, $socket) {
global $client_list;
$buf = "";
$counter = 0;
foreach($allclient as $client) {
$buf.=$client_list[$client]['nick'].", ";
$counter++;
}
socket_write($socket, "There are $counter people in this room: $buf".chr(0));
}
function send_Single($socket, $buf) {
socket_write($socket, $buf.chr(0));
}
function shutDown($allclients, $master){
global $abort;
$abort = false;
foreach($allclients as $client){
echo "$client connection closed\n";
socket_close($client);
}
echo "$master connection closed\n";
socket_close($master);
echo "Server shutdown complete\n";
}
//---- Start Socket creation for PHP 5 Socket Server -------------------------------------
if (($master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) {
echo "socket_create() failed, reason: " . socket_strerror($master) . "\n";
}else{
echo "$master socket created\n";
}
socket_set_option($master, SOL_SOCKET,SO_REUSEADDR, 1);
if (($ret = socket_bind($master, $address, $port)) < 0) {
echo "socket_bind() failed, reason: " . socket_strerror($ret) . "\n";
}else{
echo "$ret socket bound to $address:$port\n";
}
if (($ret = socket_listen($master, 5)) < 0) {
echo "socket_listen() failed, reason: " . socket_strerror($ret) . "\n";
}else{
echo "$ret listening…\n";
}
$read_sockets = array($master);
$client_list = array($master);
$abort = true;
$policy_file =
'<'.'?xml version="1.0" encoding="UTF-8"?'.'>'.
'<cross-domain-policy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.adobe.com/xml/schemas/PolicyFileSocket.xsd">'.
'<allow-access-from domain="*" to-ports="*" secure="false" />'.
'<site-control permitted-cross-domain-policies="master-only" />'.
'</cross-domain-policy>';
//---- Create Persistent Loop to continuously handle incoming socket messages ---------------------
while ($abort) {
$changed_sockets = $read_sockets;
$num_changed_sockets = socket_select($changed_sockets, $write = NULL, $except = NULL, NULL);
foreach($changed_sockets as $socket) {
if ($socket == $master) {
if (($client = socket_accept($master)) < 0) {
echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
continue;
} else {
echo "[connection]:$client\n";
array_push($read_sockets, $client);
$client_list[$client]['state'] = false;
$client_list[$client]['nick'] = "";
send_Single($client, $policy_file);
send_Single($client, "<b>Enter a nickname:<b>");
}
} else {
$bytes = socket_recv($socket, $buffer, 2048, 0);
if ($bytes == 0) {
$nick = $client_list[$socket]['nick'];
$iindex = array_search($socket, $client_list);
unset($client_list[$iindex]);
$index = array_search($socket, $read_sockets);
unset($read_sockets[$index]);
$allclients = $read_sockets;
array_shift($allclients);
if($client_list[$socket]['nick'] != "" && $client_list[$socket]['nick'] != "<policy-file-request/>"){
echo "[connection-terminated]:$socket\n";
send_Message($allclients, "$nick has left the room");
}
socket_close($socket);
}else{
if($bytes){
if($client_list[$socket]['state'] === false){
$tempBuf = trim($buffer);
$testCase = false;
foreach($read_sockets as $clients){
if ($client_list[$clients]['nick'] == $tempBuf) {
$testCase = true;
send_Single($socket, "Sorry, \"$tempBuf\" is already in use!");
send_Single($socket, "Please choose another nickname:");
break;
}
}
if(!$testCase){
$client_list[$socket]['nick'] = $tempBuf;
echo "$tempBuf assigned to $socket\n";
send_Single($socket, "Hello $tempBuf! Welcome to the game!");
$allclients = $read_sockets;
array_shift($allclients);
who($allclients, $socket);
if($client_list[$socket]['nick'] != "" && $tempBuf != "<policy-file-request/>"){
send_Message($allclients, $client_list[$socket]['nick']." has entered the game.");
}
$client_list[$socket]['state'] = true;
}
}else{
$allclients = $read_sockets;
array_shift($allclients);
if(trim($buffer) == "shut-down-server"){
shutDown($allclients, $master);
}else{
if(trim($buffer) == "/who"){
who($allclients, $socket);
}else{
send_Message($allclients, $client_list[$socket]['nick']." wrote: ".$buffer);
}
}
}
}
}
}
}
}
?>
<?php
// PHP SOCKET SERVER
error_reporting(E_ERROR);
// Configuration variables
$host = "127.0.0.1";
$port = 4041;
$max = 20;
$client = array();
// No timeouts, flush content immediatly
set_time_limit(0);
ob_implicit_flush();
// Server functions
function rLog($msg){
$msg = "[".date('Y-m-d H:i:s')."] ".$msg;
print($msg."\n");
}
// Create socket
$sock = socket_create(AF_INET,SOCK_STREAM,0) or die("[".date('Y-m-d H:i:s')."] Could not create socket\n");
// Bind to socket
socket_bind($sock,$host,$port) or die("[".date('Y-m-d H:i:s')."] Could not bind to socket\n");
// Start listening
socket_listen($sock) or die("[".date('Y-m-d H:i:s')."] Could not set up socket listener\n");
rLog("Server started at ".$host.":".$port);
// Server loop
while(true){
socket_set_block($sock);
// Setup clients listen socket for reading
$read[0] = $sock;
for($i = 0;$i<$max;$i++){
if($client[$i]['sock'] != null)
$read[$i+1] = $client[$i]['sock'];
}
// Set up a blocking call to socket_select()
$ready = socket_select($read,$write = NULL, $except = NULL, $tv_sec = NULL);
// If a new connection is being made add it to the clients array
if(in_array($sock,$read)){
for($i = 0;$i<$max;$i++){
if($client[$i]['sock']==null){
if(($client[$i]['sock'] = socket_accept($sock))<0){
rLog("socket_accept() failed: ".socket_strerror($client[$i]['sock']));
}else{
rLog("Client #".$i." connected");
}
break;
}elseif($i == $max - 1){
rLog("Too many clients");
}
}
if(--$ready <= 0)
continue;
}
for($i=0;$i<$max;$i++){
if(in_array($client[$i]['sock'],$read)){
$input = socket_read($client[$i]['sock'],1024);
if($input==null){
unset($client[$i]);
}
$n = trim($input);
$com = split(" ",$n);
if($n=="EXIT"){
if($client[$i]['sock']!=null){
// Disconnect requested
socket_close($client[$i]['sock']);
unset($client[$i]['sock']);
rLog("Disconnected(2) client #".$i);
for($p=0;$p<count($client);$p++){
socket_write($client[$p]['sock'],"DISC ".$i.chr(0));
}
if($i == $adm){
$adm = -1;
}
}
}elseif($n=="TERM"){
// Server termination requested
socket_close($sock);
rLog("Terminated server (requested by client #".$i.")");
exit();
}elseif($input){
// Strip whitespaces and write back to user
// Respond to commands
/*$output = ereg_replace("[ \t\n\r]","",$input).chr(0);
socket_write($client[$i]['sock'],$output);*/
if($n=="PING"){
socket_write($client[$i]['sock'],"PONG".chr(0));
}
if($n=="<policy-file-request/>"){
rLog("Client #".$i." requested a policy file…");
$cdmp="<?xml version=\"1.0\" encoding=\"UTF-8\"?><cross-domain-policy xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://www.adobe.com/xml/schemas/PolicyFileSocket.xsd\"><allow-access-from domain=\"*\" to-ports=\"*\" secure=\"false\" /><site-control permitted-cross-domain-policies=\"master-only\" /></cross-domain-policy>";
socket_write($client[$i]['sock'],$cdmp.chr(0));
socket_close($client[$i]['sock']);
unset($client[$i]);
$cdmp="";
}
}
}else{
//if($client[$i]['sock']!=null){
// Close the socket
//socket_close($client[$i]['sock']);
//unset($client[$i]);
//rLog("Disconnected(1) client #".$i);
//}
}
}
}
// Close the master sockets
socket_close($sock);
?>
http://www.functionblog.com/?p=67=1
Threading
Therading is impossible in Flash. But:
[Idea] Using LocalConnection between mutliple Flash embedded in same page ? (depend browser, but maybe all instance are in same os thread)
public class PseudoThread extends EventDispatcher
{
public function PseudoThread(parent:Sprite, threadFunction:Function, threadObject:Object):void
{
fn = threadFunction;
obj = threadObject;
// add high priority listener for ENTER_FRAME
parent.stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler, false, 100);
parent.stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
parent.stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
thread = new Sprite();
parent.addChild(thread);
thread.addEventListener(Event.RENDER, renderHandler);
}
// number of milliseconds we think it takes to render the screen
public var RENDER_DEDUCTION:int = 10;
private var fn:Function;
private var obj:Object;
private var thread:Sprite;
private var start:Number;
private var due:Number;
private var mouseEvent:Boolean;
private var keyEvent:Boolean;
private function enterFrameHandler(event:Event):void
{
start = getTimer();
var fr:Number = Math.floor(1000 / thread.stage.frameRate);
due = start + fr;
thread.stage.invalidate();
thread.graphics.clear();
thread.graphics.moveTo(0, 0);
thread.graphics.lineTo(0, 0);
}
private function renderHandler(event:Event):void
{
if (mouseEvent || keyEvent)
due -= RENDER_DEDUCTION;
while (getTimer() < due)
{
if (!fn(obj))
{
if (!thread.parent)
return;
thread.stage.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
thread.stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
thread.stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
thread.parent.removeChild(thread);
thread.removeEventListener(Event.RENDER, renderHandler);
dispatchEvent(new Event("threadComplete"));
}
}
mouseEvent = false;
keyEvent = false;
}
private function mouseMoveHandler(event:Event):void
{
mouseEvent = true;
}
private function keyDownHandler(event:Event):void
{
keyEvent = true;
}
}
Progressive SWF loading ("use later" code/assets or embedded preloader)
//...
public class MyClass1 extends MovieClip
//...
//...
[Frame(factoryClass="MyClass1")]
public class MyClass2
//...
//...
[Frame(factoryClass="MyClass2")]
public class MyClass3
//...
Compile a SWF following:
Frame 1
Include MyClass1
Create an instance of MyClass1 and use it as root class
Frame 2
Include MyClass2
Frame 3
Include MyClass3
You must to compile MyClass3 as main class
MyClass1 must extends MovieClip (you can also extends Sprite, but some things will not work)
You can check loading progression with loaderInfo's progress event
You can check also frame loading (framesLoaded/totalFrames)
To ask FlashPlayer to parse a frame (when is loaded), you must to play it (with nextFrame() or gotoAndStop())
MyClass2 and MyClass3 could not extends DisplayObject and are not executed
If you want to use SWF metadata tag, you must use it in main class (which use to compile application), here MyClass3
If you want to add an extra class in a specific frame use [Frame(extraClass="MyAsset")]
Example (frames):
Loading
Libraries (classes …)
Main
package { import flash.display.Sprite;
//This tells the compiler to create a new frame this main class
[Frame(factoryClass="PreloadedMain")]
public class PreloadedMain extends Sprite
{
public function PreloadedMain():void
{
}
}
}
package {
import flash.display.DisplayObject;
import flash.display.MovieClip;
import flash.events.Event;
import flash.utils.getDefinitionByName;
public class Main extends MovieClip
{
public function Main():void
{
//Stop the timeline
stop();
//Set an eventlistener for the animation
this.addEventListener(Event.ENTER_FRAME, this.enterFrameListener);
}
//Draw a bar, or your preloader of choice
public function enterFrameListener(event:Event):void
{
if(this.framesLoaded == this.totalFrames)
{
this.removeEventListener(Event.ENTER_FRAME, this.enterFrameListener);
//Move to the next frame when we're done
this.nextFrame();
//And initialize our main class
//Get our main class
var mainClass:Class = Class(getDefinitionByName("PreloadedMain"));
if(mainClass)
{
//And instantiate it
var app:Object = new mainClass();
//finally we add it to the DisplayList
this.addChild(app as DisplayObject);
}
}
}
}
<d:Sprite xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:d="flash.display.*">
<mx:Metadata>
[SWF(width="900", height="480", backgroundColor="#ffffff")]
</mx:Metadata>
<mx:Script>
<![CDATA[
public function sayHi():void
{
trace("hello world");
}
]]>
</mx:Script>
</d:Sprite>
<w:Element xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:d="flash.display.*" xmlns:t="flash.text.*" xmlns:w="*">
<d:Shape />
<w:Element>
<t:TextField text="Test" />
</w:Element>
</w:Element>
package
{
import flash.display.DisplayObject;
import flash.display.Sprite;
[DefaultProperty("children")]
public class Element extends Sprite
{
private var _children:Vector.<DisplayObject> = new Vector.<DisplayObject>();
/**
* Array of DisplayObject instances to be added as children
*/
public function get children():Vector.<DisplayObject>
{
return _children;
}
public function set children( value:Vector.<DisplayObject> ):void
{
if ( _children != value )
{
_children = value;
for each(var child:DisplayObject in value)
addChild(child);
}
}
}
}
Array implementation (http://wiki.ecmascript.org/doku.php?id=discussion:builtin_classes) can be found in Tamarin
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.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 [Open Source Virtual Machine.].
*
* The Initial Developer of the Original Code is
* Adobe System Incorporated.
* Portions created by the Initial Developer are Copyright (C) 2004-2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
- Adobe AS3 Team
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package
{
public dynamic class Array extends Object
{
// option flags for sort and sortOn
public static const CASEINSENSITIVE:uint = 1;
public static const DESCENDING:uint = 2;
public static const UNIQUESORT:uint = 4;
public static const RETURNINDEXEDARRAY:uint = 8;
public static const NUMERIC:uint = 16;
// E262 {DontEnum, DontDelete}
public native function get length():uint
public native function set length(newLength:uint)
// Array.length = 1 per ES3
public static const length:int = 1
// ECMA 15.4.2.2
public function Array(...args)
{
var n:uint = args.length
if (n == 1 && (args[0] is Number))
{
var dlen:Number = args[0];
var ulen:uint = dlen
if (ulen != dlen)
Error.throwError( RangeError, 1005 /*kArrayIndexNotIntegerError*/, dlen );
length = ulen;
}
else
{
length = n
for (var i:uint=0; i < n; i++)
this[i] = args[i]
}
}
/**
15.4.4.5 Array.prototype.join (separator)
The elements of the array are converted to strings, and these strings are then concatenated, separated by
occurrences of the separator. If no separator is provided, a single comma is used as the separator.
The join method takes one argument, separator, and performs the following steps:
1. Call the [[Get]] method of this object with argument "length".
2. Call ToUint32(Result(1)).
3. If separator is undefined, let separator be the single-character string ",".
4. Call ToString(separator).
5. If Result(2) is zero, return the empty string.
6. Call the [[Get]] method of this object with argument "0".
7. If Result(6) is undefined or null, use the empty string; otherwise, call ToString(Result(6)).
8. Let R be Result(7).
9. Let k be 1.
10. If k equals Result(2), return R.
11. Let S be a string value produced by concatenating R and Result(4).
12. Call the [[Get]] method of this object with argument ToString(k).
13. If Result(12) is undefined or null, use the empty string; otherwise, call ToString(Result(12)).
14. Let R be a string value produced by concatenating S and Result(13).
15. Increase k by 1.
16. Go to step 10.
*/
private static function _join(o, sep):String
{
var s:String = (sep === undefined) ? "," : String(sep)
var out:String = ""
for (var i:uint = 0, n:uint=uint(o.length); i < n; i++)
{
var x = o[i]
if (x != null)
out += x
if (i+1 < n)
out += s
}
return out
}
AS3 function join(sep=void 0):String
{
return _join(this, sep)
}
prototype.join = function(sep=void 0):String
{
return _join(this, sep)
}
private static native function _pop(o)
AS3 native function pop()
prototype.pop = function()
{
return _pop(this)
}
/**
15.4.4.2 Array.prototype.toString ( )
The result of calling this function is the same as if the built-in join method were invoked for this object with no
argument.
The toString function is not generic; it throws a TypeError exception if its this value is not an Array object.
Therefore, it cannot be transferred to other kinds of objects for use as a method.
*/
prototype.toString = function():String
{
var a:Array = this // TypeError if not compatible
return _join(a, ",");
}
/**
15.4.4.3 Array.prototype.toLocaleString ( )
The elements of the array are converted to strings using their toLocaleString methods, and these strings are
then concatenated, separated by occurrences of a separator string that has been derived in an implementationdefined
locale-specific way. The result of calling this function is intended to be analogous to the result of
toString, except that the result of this function is intended to be locale-specific.
The result is calculated as follows:
1. Call the [[Get]] method of this object with argument "length".
2. Call ToUint32(Result(1)).
3. Let separator be the list-separator string appropriate for the host environment’s current locale (this is derived in
an implementation-defined way).
4. Call ToString(separator).
5. If Result(2) is zero, return the empty string.
6. Call the [[Get]] method of this object with argument "0".
7. If Result(6) is undefined or null, use the empty string; otherwise, call ToObject(Result(6)).toLocaleString().
8. Let R be Result(7).
9. Let k be 1.
10. If k equals Result(2), return R.
11. Let S be a string value produced by concatenating R and Result(4).
12. Call the [[Get]] method of this object with argument ToString(k).
13. If Result(12) is undefined or null, use the empty string; otherwise, call ToObject(Result(12)).toLocaleString().
14. Let R be a string value produced by concatenating S and Result(13).
15. Increase k by 1.
16. Go to step 10.
The toLocaleString function is not generic; it throws a TypeError exception if its this value is not an Array
object. Therefore, it cannot be transferred to other kinds of objects for use as a method.
*/
prototype.toLocaleString = function():String
{
var a:Array = this // TypeError if not compatible
var out:String = ""
for (var i:uint = 0, n:uint=a.length; i < n; i++)
{
var x = a[i]
if (x != null)
out += x.toLocaleString()
if (i+1 < n)
out += ","
}
return out
}
/**
When the push method is called with zero or more arguments item1, item2, etc., the following steps are taken:
1. Call the [[Get]] method of this object with argument "length".
2. Let n be the result of calling ToUint32(Result(1)).
3. Get the next argument in the argument list; if there are no more arguments, go to step 7.
4. Call the [[Put]] method of this object with arguments ToString(n) and Result(3).
5. Increase n by 1.
6. Go to step 3.
7. Call the [[Put]] method of this object with arguments "length" and n.
8. Return n.
The length property of the push method is 1.
NOTE The push function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be
transferred to other kinds of objects for use as a method. Whether the push function can be applied successfully to a host object
is implementation-dependent.
*/
AS3 native function push(...args):uint
prototype.push = function(...args):uint
{
var n:uint = uint(this.length)
for (var i:uint=0, argc:uint=args.length; i < argc; i++)
this[n++] = args[i]
this.length = n
return n
}
private static native function _reverse(o)
AS3 function reverse():Array
{
return _reverse(this) // return will cast to Array
}
prototype.reverse = function()
{
return _reverse(this)
}
private static native function _concat(o, args:Array):Array
AS3 function concat(...args):Array
{
return _concat(this, args)
}
prototype.concat = function(...args):Array
{
return _concat(this, args)
}
private static native function _shift(o)
AS3 function shift()
{
return _shift(this)
}
prototype.shift = function()
{
return _shift(this)
}
private static native function _slice(o, A:Number, B:Number):Array
AS3 function slice(A=0, B=0xffffffff):Array
{
return _slice(this, Number(A), Number(B))
}
prototype.slice = function(A=0, B=0xffffffff):Array
{
return _slice(this, Number(A), Number(B))
}
/**
15.4.4.13 Array.prototype.unshift ( [ item1 [ , item2 [ , … ] ] ] )
The arguments are prepended to the start of the array, such that their order within the array is the same as the
order in which they appear in the argument list.
When the unshift method is called with zero or more arguments item1, item2, etc., the following steps are taken:
1. Call the [[Get]] method of this object with argument "length".
2. Call ToUint32(Result(1)).
3. Compute the number of arguments.
4. Let k be Result(2).
5. If k is zero, go to step 15.
6. Call ToString(k–1).
7. Call ToString(k+Result(3)–1).
8. If this object has a property named by Result(6), go to step 9; but if this object has no property named by
Result(6), then go to step 12.
9. Call the [[Get]] method of this object with argument Result(6).
10. Call the [[Put]] method of this object with arguments Result(7) and Result(9).
11. Go to step 13.
12. Call the [[Delete]] method of this object with argument Result(7).
13. Decrease k by 1.
14. Go to step 5.
15. Let k be 0.
16. Get the next argument in the part of the argument list that starts with item1; if there are no more arguments, go
to step 21.
17. Call ToString(k).
18. Call the [[Put]] method of this object with arguments Result(17) and Result(16).
19. Increase k by 1.
20. Go to step 16.
21. Call the [[Put]] method of this object with arguments "length" and (Result(2)+Result(3)).
22. Return (Result(2)+Result(3)).
The length property of the unshift method is 1.
NOTE The unshift function is intentionally generic; it does not require that its this value be an Array object. Therefore it can
be transferred to other kinds of objects for use as a method. Whether the unshift function can be applied successfully to a
host object is implementation-dependent.
*/
native AS3 function unshift(...args):uint
prototype.unshift = function(...args):uint
{
var len:uint = uint(this.length)
var argc:uint = args.length
var k:uint
for (k=len; k > 0; )
{
k--
var d:uint = k+argc
if (k in this)
this[d] = this[k]
else
delete this[d]
}
for (var i:uint = 0; i < argc; i++)
this[k++] = args[i]
len += argc
this.length = len
return len
}
private static native function _splice(o, args:Array):Array
// splice with zero args returns undefined. All other cases return Array.
AS3 function splice(...args)
{
if (!args.length)
return undefined;
return _splice(this, args)
}
prototype.splice = function(...args)
{
if (!args.length)
return undefined;
return _splice(this, args)
}
// sort can return an Array or a Number (unique sort option)
private static native function _sort(o, args:Array)
AS3 function sort(...args)
{
return _sort (this, args);
}
prototype.sort = function(...args)
{
return _sort (this, args);
}
private static native function _sortOn(o, names, options)
AS3 function sortOn(names, options=0, ...ignored)
{
// this is our own addition so we don't have to make names be optional
return _sortOn(this, names, options);
}
prototype.sortOn = function(names, options=0, ...ignored)
{
return _sortOn(this, names, options)
}
// Array extensions that are in Mozilla...
// http://developer.mozilla.org/en/docs..._Objects:Array
//
// These all work on generic objects (array like objects) as well as arrays
private static native function _indexOf (o, searchElement, fromIndex:int):int;
AS3 function indexOf(searchElement, fromIndex=0):int
{
return _indexOf (this, searchElement, int(fromIndex));
}
prototype.indexOf = function(searchElement, fromIndex=0):int
{
return _indexOf (this, searchElement, int(fromIndex));
}
private static native function _lastIndexOf (o, searchElement, fromIndex:int=0):int;
AS3 function lastIndexOf(searchElement, fromIndex=0x7fffffff):int
{
return _lastIndexOf (this, searchElement, int(fromIndex));
}
prototype.lastIndexOf = function(searchElement, fromIndex=0x7fffffff):int
{
return _lastIndexOf (this, searchElement, int(fromIndex));
}
// Returns true if every element in this array satisfies the provided testing function.
private static native function _every(o, callback:Function, thisObject):Boolean;
AS3 function every(callback:Function, thisObject=null):Boolean
{
return _every (this, callback, thisObject);
}
prototype.every = function(callback:Function, thisObject=null):Boolean
{
return _every (this, callback, thisObject);
}
// Creates a new array with all elements that pass the test implemented by the provided function.
private static native function _filter(o, callback:Function, thisObject):Array;
AS3 function filter(callback:Function, thisObject=null):Array
{
return _filter (this, callback, thisObject);
}
prototype.filter = function(callback:Function, thisObject=null):Array
{
return _filter (this, callback, thisObject);
}
// Calls a function for each element in the array.
private static native function _forEach(o, callback:Function, thisObject):void;
AS3 function forEach(callback:Function, thisObject=null):void
{
_forEach (this, callback, thisObject);
}
prototype.forEach = function(callback:Function, thisObject=null):void
{
_forEach (this, callback, thisObject);
}
// Creates a new array with the results of calling a provided function on every element in this array.
private native static function _map(o, callback:Function, thisObject):Array;
AS3 function map(callback:Function, thisObject=null):Array
{
return _map (this, callback, thisObject);
}
prototype.map = function(callback:Function, thisObject=null):Array
{
return _map (this, callback, thisObject);
}
// Returns true if at least one element in this array satisfies the provided testing function.
private static native function _some(o, callback:Function, thisObject):Boolean;
AS3 function some(callback:Function, thisObject=null):Boolean
{
return _some (this, callback, thisObject);
}
prototype.some = function(callback:Function, thisObject=null):Boolean
{
return _some (this, callback, thisObject);
}
_dontEnumPrototype(prototype);
}
}
Internals
Sound use URLStream? (error #2029)
flash.external::ExternalInterface$/_callIn
public::trace
ApplicationDomain.currentDomain.getDefinition("trace") as Function
import flash.trace.Trace
public function traceListener(line:String, index:int, method:Sring, args:String):void
{
trace("@" + index + " - " + line);
trace(method + "(" + args + ")");
}
Equality
null false 0 "" NaN
------------------------------------------------
isNaN() - - - - x
== "" - x x x -
=== "" - - - x -
== null x - - - -
=== null x - - - -
== 0 - x x x -
=== 0 - - x - -
== false - x x x -
=== false - x - - -
is Number - - x - x
is String - - - x -
is Boolean - x - - -
is Object - x x x x
Notice that NaN is actually a Number and an Object, that 0 == "" == false and that false is actually an Object