The aim of this document is to gather informations, snippets, tips and links not provided by any official documentation, related to Flash Platform or others ECMAScript languages.
Flash renames bitmap fonts and adds the suffix: _{size}pt_st
, where {size}
is the bitamp size of the font.
Exemple:
Verdana_12pt_st
Arial_12pt_st
In FlashPlayer 9, to apply alpha, use filters
, cacheAsBitmap or blend mode "layer"
textField.filters = [new BlurFilter(0,0,0)];//use emtpy filter to cache text
//or
textField.blendMode = BlendMode.LAYER;
//and finaly
textField.alpha = 0.5;
For other effect (rotation, scale, etc.) draw TextField
in a BitmapData
In FlashPlayer 10, no more problems with alpha, but remain for transfrom effects like rotation, scale, etc.
In FlashPlayer 10 flash.text.engine natively support it
flash.external::ExternalInterface$/_callIn
6 to 9 month for all new version to reach ~90% of adoption
/**
*
* Copyright 2007
*
* Paulius Uza
* http://www.uza.lt
* http://www.uza.lt/blog/2007/08/solved-right-click-in-as3
*
* Dan Florio
* http://www.polygeek.com
*
* Project website:
* http://code.google.com/p/custom-context-menu/
*
* --
* RightClick for Flash Player.
* Version 0.6.2
*
*/
var RightClick = {
/**
* Constructor
*/
init: function () {
this.FlashObjectID = "customRightClick";
this.FlashContainerID = "flashcontent";
this.Cache = this.FlashObjectID;
if(window.addEventListener){
window.addEventListener("mousedown", this.onGeckoMouse(), true);
} else {
document.getElementById(this.FlashContainerID).onmouseup = function() { document.getElementById(RightClick.FlashContainerID).releaseCapture(); }
document.oncontextmenu = function(){ if(window.event.srcElement.id == RightClick.FlashObjectID) { return false; } else { RightClick.Cache = "nan"; }}
document.getElementById(this.FlashContainerID).onmousedown = RightClick.onIEMouse;
}
},
/**
* GECKO / WEBKIT event overkill
* @param {Object} eventObject
*/
killEvents: function(eventObject) {
if(eventObject) {
if (eventObject.stopPropagation) eventObject.stopPropagation();
if (eventObject.preventDefault) eventObject.preventDefault();
if (eventObject.preventCapture) eventObject.preventCapture();
if (eventObject.preventBubble) eventObject.preventBubble();
}
},
/**
* GECKO / WEBKIT call right click
* @param {Object} ev
*/
onGeckoMouse: function(ev) {
return function(ev) {
if (ev.button != 0) {
RightClick.killEvents(ev);
if(ev.target.id == RightClick.FlashObjectID && RightClick.Cache == RightClick.FlashObjectID) {
RightClick.call();
}
RightClick.Cache = ev.target.id;
}
}
},
/**
* IE call right click
* @param {Object} ev
*/
onIEMouse: function() {
if (event.button > 1) {
if(window.event.srcElement.id == RightClick.FlashObjectID && RightClick.Cache == RightClick.FlashObjectID) {
RightClick.call();
}
document.getElementById(RightClick.FlashContainerID).setCapture();
if(window.event.srcElement.id)
RightClick.Cache = window.event.srcElement.id;
}
},
/**
* Main call to Flash External Interface
*/
call: function() {
document.getElementById(this.FlashObjectID).rightClick();
}
}
ExternalInterface
JavaScript evaluationExternalInterface
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.
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; }
FLfile.runCommandLine("command line here");
var frame = fl.getDocumentDOM().timelines[0].layers[0].frames[0];
var headerText = "[SWF(width=800, height=800, backgroundColor=0xffffff, frameRate=24)]\n"
+ "stage.align = StageAlign.TOP_LEFT;\n"
+ "stage.scaleMode = StageScaleMode.NO_SCALE;\n\n";
frame.actionScript = headerText + frame.actionScript;
[Transient]
metadatapackage 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()
-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;
-define=namespace::variable_name,value
CONDITIONAL_COMPILATION::value
{
//Do something only when compilation condition is verified
}
if(some condition)
{
//Do something
}
else
{
CONDITIONAL_COMPILATION::value
{
//Something only when compilation condition is verified
}
}
CONDITIONAL_COMPILATION::value = 'true'
Inline
package { CONFIG::debugging public class MyClass { //some declarations } CONFIG::release public class MyClass { //some declarations } }
CONFIG::debugging = 'true' CONFIG::release = '!CONFIG::debugging'
private static const companyName:String = NAMES::Company;
NAMES::Company = '"Company name"'
Conditional compilation is string replacement
CONDITIONAL_COMPILATION::value = '1 > 2' CONDITIONAL_COMPILATION::value1 = 'false' CONDITIONAL_COMPILATION::value2 = 'CONDITIONAL_COMPILATION::value1 && false'
Since CS5, FLA file format is an XML based format. May be compressed in a ZIP file.
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Original Author <alessandro@sephiroth.it> |
// +----------------------------------------------------------------------+
//http://www.sephiroth.it/swfreader.php
/**
* required base PEAR package
*/
require_once "PEAR.php";
/**
* Required package File for I/O operations
*/
require_once "File.php";
/**
* error constant
*/
define('PEAR_SWF_ID_ERR', 1);
/**
* Base SWF class
*
* This class requires the File PEAR.
* Read the SWF header informations and return an
* associative array with the property of the SWF File, the result array
* will contain framerate, framecount, background color, compression, filetype
* version and movie size.
* <code>
* <?php
* require_once "File/File_SWF.php";
* $file = "any_file.swf";
*
* $swf = &new File_SWF($file);
* if($swf->isValid){
* $result = $swf->stat();
* print_r($result);
* }
* <?
* </code>
* @author Alessandro Crugnola <alessandro@sephiroth.it>
* @access public
* @version 0.2
* @package File_SWF
*/
class File_SWF
{
/**
* current unpacked binary string
* @var mixed
*/
var $current = "";
/**
* internal pointer
* @var integer
*/
var $position = 0;
/**
* use zlib compression
* @var boolean
*/
var $compression = 0;
/**
* current position
* @var integer
*/
var $point = 0;
/**
* is a valid swf
* @var boolean
* @access private
*/
var $isValid = 0;
/**
* stirng file name to parse
* @var string
*/
var $file = "";
/**
* determine if file is protected
* @var boolean
*/
var $protected = false;
/**
* password for protected files
* @var mixed
*/
var $password;
/**
* Deconstructor
* does anything right now
* @access public
*/
function _File_SWF()
{
}
/**
* Costructor
* creates a new SWF object
* reads the given file and parse it
* @param string $file file to parse
* @access public
*/
function File_SWF($file="")
{
$this->compression = 0;
$this->isValid = 0;
$this->point = 0;
$this->file = $file;
$head = File::read($this->file, 3);
if(PEAR::isError($head)){
return $head;
}
File::rewind($this->file, "rb");
if($head == "CWS"){
$data = File::read($this->file, 8);
$_data = gzuncompress(File::read($this->file, filesize($this->file)));
$data = $data . $_data;
$this->data = $data;
$this->compression = 1;
$this->isValid = 1;
} else if ($head == "FWS"){
$this->data = File::read($this->file, filesize($this->file));
$this->isValid = 1;
} else {
/**
* invalid SWF file, or invalid head tag found
*/
$this->isValid = 0;
}
File::close($this->file, "rb");
}
/**
* Is a valid SWF file
* @return boolean
* @access public
*/
function is_valid()
{
return $this->isValid;
}
/**
* Return if swf file is protected from import
* @return boolean
* @access public
*/
function getProtected()
{
if($this->getVersion() >= 8){
$this->_seek(31);
} else {
$this->_seek(26);
}
$data = $this->_readTag();
$tag = $data[0];
$this->protected = $tag == 24;
return $this->protected;
}
/**
* Define import protection for the SWF
* @param boolean $protect define is file must be protected
* @access public
*/
function setProtected($protect)
{
if($protect and !$this->protected){
if($this->getVersion() >= 8){
$pre = substr($this->data, 0, 31);
$post = substr($this->data, 31);
} else {
$pre = substr($this->data, 0, 26);
$post = substr($this->data, 26);
}
$middle = pack("v", 1536);
$this->data = $pre . $middle . $post;
$this->password = 0;
$this->protected = true;
} else if(!$protect and $this->protected){
if($this->getVersion() >= 8){
$pos = 31;
} else {
$pos = 26;
}
$this->_seek($pos);
if($this->_readData()){
$this->data = substr($this->data,0, $pos) . substr($this->data, $this->point - (is_string($this->password) == 1 ? 0 : 1));
}
}
}
/**
* Return the current SWF frame rate
* @return mixed interger frame rate in fps or Error if invalid file
* @access public
*/
function getFrameRate()
{
if(!$this->is_valid()){
return PEAR::raiseError("Invalid SWF head TAG found in " . $this->file, PEAR_SWF_ID_ERR);
}
if($this->getVersion() >= 8){
$this->_seek(16);
} else {
$this->_seek(17);
}
$fps = unpack('vrate',$this->_read(2));
return $fps['rate']/256;
}
/**
* Set the new Frame Rate
* @access public
*/
function setFrameRate($num)
{
if(!$this->is_valid()){
return;
}
$num = intval($num);
if($num > 0 and $num <= 120){
$fps = pack('v', $num*256);
if($this->getVersion() >= 8){
$this->_seek(16);
$this->data = substr($this->data, 0, 16) . $fps . substr($this->data, 18);
} else {
$this->_seek(17);
$this->data = substr($this->data, 0, 17) . $fps . substr($this->data, 19);
}
}
}
/**
* Return the current number of frames
* @return mixed interger or error if invalid file format
* @access public
*/
function getFrameCount()
{
if(!$this->is_valid()){
return PEAR::raiseError("Invalid SWF head TAG found in " . $this->file, PEAR_SWF_ID_ERR);
}
if($this->getVersion() >= 8){
$this->_seek(18);
} else {
$this->_seek(19);
}
return $this->_readshort();
}
/**
* Return the current movie size in pixel
* @return mixed array or error if invalid file format
* @access public
*/
function getMovieSize()
{
if(!$this->is_valid()){
return PEAR::raiseError("Invalid SWF head TAG found in " . $this->file, PEAR_SWF_ID_ERR);
}
$this->_seek(8);
return $this->_readRect();
}
/**
* Return the current file type (CWS, FWS)
* @return mixed string or error if invalid file format
* @access public
*/
function getFileType()
{
if(!$this->is_valid()){
return PEAR::raiseError("Invalid SWF head TAG found in " . $this->file, PEAR_SWF_ID_ERR);
}
$this->_seek(0);
return $this->_read(3);
}
/**
* Return the current compression used
* @return mixed interger or error if invalid file format
* @access public
*/
function getCompression()
{
if(!$this->is_valid()){
return PEAR::raiseError("Invalid SWF head TAG found in " . $this->file, PEAR_SWF_ID_ERR);
}
return $this->compression;
}
/**
* Set the compression
* @return string based on the compression used
* @param integer $mode compression on/off
* @access public
*/
function setCompression($mode = 0)
{
if(!$this->is_valid()){
return;
}
$data = "";
$real_size = pack("V", strlen($this->data));
$this->data = substr($this->data, 0, 4) . $real_size . substr($this->data, 8, strlen($this->data));
if($mode == 0){
$this->compression = 0;
$this->data = "FWS" . substr($this->data, 3);
$_n1 = substr($this->data, 0, 8);
$_n2 = substr($this->data, 8, strlen($this->data));
$data = $_n1 . $_n2;
} else if($mode == 1){
$this->compression = 1;
$this->data = "CWS" . substr($this->data, 3);
$_n1 = substr($this->data, 0, 8);
$_n2 = substr($this->data, 8, strlen($this->data));
$_n3 = gzcompress($_n2);
$data = $_n1 . $_n3;
}
return $data;
}
/**
* Return the current version of player used
* @return mixed interger or error if invalid file format
* @access public
*/
function getVersion()
{
if(!$this->is_valid()){
return PEAR::raiseError("Invalid SWF head TAG found in " . $this->file, PEAR_SWF_ID_ERR);
}
$this->_seek(3);
return $this->_readbyte();
}
/**
* Return the current SWF file size
* @return mixed interger or error if invalid file format
* @access public
*/
function filesize()
{
if(!$this->is_valid()){
return PEAR::raiseError("Invalid SWF head TAG found in " . $this->file, PEAR_SWF_ID_ERR);
}
$this->_seek(4);
$real_size = unpack("Vnum", $this->_read(4));
if($this->getCompression()){
$n = $this->data;
$n = "CWS" . substr($n, 3, 8) . gzcompress(substr($n, 8, strlen($n)));
$file_size = strlen($n) -3;
} else {
$file_size = strlen($this->data)-3;
}
return array($file_size, $real_size['num'], "compressed" => $file_size, "real" => $real_size['num']);
}
/**
* Return the current background color
* @return mixed array or error if invalid file format
* @access public
*/
function getBackgroundColor()
{
if(!$this->is_valid()){
return PEAR::raiseError("Invalid SWF head TAG found in " . $this->file, PEAR_SWF_ID_ERR);
}
if($this->getVersion() >= 8){
$this->_seek(26);
} else {
$this->_seek(21);
}
return $this->_readData();
}
/**
* Set the new background color
* @param integer $r (0,255)
* @param integer $g (0,255)
* @param integer $b (0,255)
* @access public
*/
function setBackgroundColor($r=0, $g=0, $b=0)
{
if(!$this->is_valid()){
return;
}
$color = pack("C", $r);
$color .= pack("C", $g);
$color .= pack("C", $b);
if($this->getVersion() >= 8){
$data = substr($this->data, 0, 28);
$data .= $color;
$this->data = $data . substr($this->data, 31, strlen($this->data));
} else {
$data = substr($this->data, 0, 23);
$data .= $color;
$this->data = $data . substr($this->data, 26, strlen($this->data));
}
}
/**
* Save current swf as a new file
* @param string $filename filename
* @param boolean $overwrite overwrite existing file
* @return boolean true if saved succesfully
* @access public
*/
function write($filename, $overwrite = 1)
{
if(!$this->is_valid()){
return false;
}
if(is_writeable(dirname($filename))){
if(is_file($filename)){
if($overwrite == 0){
return false;
}
}
$newdata = $this->setCompression($this->getCompression());
File::write ($filename, $newdata, $mode = "wb");
File::close($filename, "wb");
return true;
} else {
return false;
}
}
/**
* reads the SWF header
* @return mixed associative array or error on fault
* @access private
*/
function stat()
{
if(!$this->is_valid()){
return PEAR::raiseError("Invalid SWF head TAG found in " . $this->file, PEAR_SWF_ID_ERR);
}
$filetype = $this->getFileType();
$version = $this->getVersion();
$filelength = $this->filesize();
$rect = $this->getMovieSize();
$framerate = $this->getFrameRate();
$framecount = $this->getFrameCount();
$background = $this->getBackgroundColor();
$protection = $this->getProtected();
return array(
"zlib-compression" => $this->getCompression(),
"fileType" => $filetype,
"version" => $version,
"fileSize" => $filelength,
"frameRate" => $framerate,
"frameCount" => $framecount,
"movieSize" => $rect,
"background" => $background,
"protected" => $protection,
);
}
/**
* read tag type, tag length
* @return array
* @access private
*/
function _readTag()
{
$n = $this->_readshort();
if($n == 0)
{
return false;
}
$tagn = $n>>6;
$length = $n&0x3F;
if($length == 0x3F)
{
$length = $this->_readlong();
}
return array($tagn,$length);
}
/**
* read long
* @access private
*/
function _readlong(){
$ret = unpack("Nnum", $this->_read(4));
return $ret['num'];
}
/**
* read data of next tag
* @return array
* @access private
*/
function _readData()
{
$tag = $this->_readTag();
$tagn = $tag[0];
$length = $tag[1];
if($tagn == 9)
{
$r = $this->_readbyte();
$g = $this->_readbyte();
$b = $this->_readbyte();
$data = array($r,$g,$b, "hex" => sprintf("#%X%X%X", $r, $g, $b));
return $data;
} else if($tagn == 24)
{
if($this->_readbyte() == 0x00){
$this->_readbyte();
$this->password = $this->_readstring();
} else {
$this->password = 0;
}
return true;
}
return array();
}
/**
* read a string
* @return string
* @access private
*/
function _readstring()
{
$s = "";
while(true){
$ch = $this->_read(1);
if($this->point > strlen($this->data)){
break;
}
if($ch == "\x00"){
break;
}
$s .= $ch;
}
return $s;
}
/**
* read internal data file
* @param integer $n number of byte to read
* @return array
* @access private
*/
function _read($n)
{
$ret = substr($this->data, $this->point, $n);
$this->point += $n;
return $ret;
}
/**
* move the internal pointer
* @param integer $num
* @access private
*/
function _seek($num){
if($num < 0){
$num = 0;
} else if($num > strlen($this->data)){
$num = strlen($this->data);
}
$this->point = $num;
}
/**
* read short
* @return string
* @access private
*/
function _readshort(){
$pack = unpack('vshort',$this->_read(2));
return $pack['short'];
}
/**
* read single byte
* @return string
* @access private
*/
function _readByte(){
$ret = unpack("Cbyte",$this->_read(1));
return $ret['byte'];
}
/**
* read a rect type
* @return rect
* @access private
*/
function _readRect(){
$this->_begin();
$l = $this->_readbits(5);
$xmin = $this->_readbits($l)/20;
$xmax = $this->_readbits($l)/20;
$ymin = $this->_readbits($l)/20;
$ymax = $this->_readbits($l)/20;
$rect = array(
$xmax,
$ymax,
"width" => $xmax,
"height" => $ymax
);
return $rect;
}
/**
* read position internal to rect
* @access private
*/
function _incpos(){
$this->position += 1;
if($this->position>8){
$this->position = 1;
$this->current = $this->_readbyte();
}
}
/**
* read bites
* @param integer $nbits number of bits to read
* @return string
* @access private
*/
function _readbits($nbits){
$n = 0;
$r = 0;
while($n < $nbits){
$r = ($r<<1) + $this->_getbits($this->position);
$this->_incpos();
$n += 1;
}
return $r;
}
/**
* getbits
* @param integer $n
* @return long
* @access private
*/
function _getbits($n){
return ($this->current>>(8-$n))&1;
}
/**
* begin reading of rect object
* @access private
*/
function _begin(){
$this->current = $this->_readbyte();
$this->position = 1;
}
}
?>
xml.setNotification(callback:Function);
function callback(currentTarget:Object, type:String, target:Object, value:Object, detail:Object):void;
Types:
attributeAdded
attributeChanged
attributeRemoved
nodeAdded
nodeChanged
nodeRemoved
nameSet
namespaceAdded
namespaceRemoved
namespaceSet
textSet
Exemple:
<node name="Mike" age="34"><address><![CDATA[Fake address]]></address></node>
Get in items
all XML nodes node
:
xml.node.(items.push(new User(@name, uint(@age))));
The same but with address:
xml.node.(
items.push(item = new User(@name, uint(@age))),
item.address = address[0].toString()
);
Get all nodes with age greater than 30:
xml.node.(int(@age)>30).(
items.push(item = new User(@name, uint(@age))),
item.address = address[0].toString()
);
The same but with only one cycle
xml.node.(
// ?: condition
int(@age)>30 ? (
// if condition equals TRUE actions, separated by commas
item = new User(@name, uint(@age)),
items.push(item),
item.address = address[0].toString()
) : false // if condition equals FALSE actions
);
Child SWF uses parent domain definitions. If defined there, otherwise its own.
var childDefinitions:LoaderContext = new LoaderContext();
childDefinitions.applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);
child SWF adds its unique definitions to parent SWF; both SWFs share the same domain child SWFs definitions do not overwrite parents
var addedDefinitions:LoaderContext = new LoaderContext();
addedDefinitions.applicationDomain = ApplicationDomain.currentDomain;
child SWF domain is completely separate and each SWF uses its own definitions
var separateDefinitions:LoaderContext = new LoaderContext();
separateDefinitions.applicationDomain = new ApplicationDomain();
set loader context in load()
myLoader.load(request, separateDefinitions);
//http://www.morearty.com/blog/2009/04/01/aprilscript-actionscript-worst-practices/
package {
import flash.display.*
import flash.text.*
public class AprilFools extends Sprite {
エイプリルフール var Number = 4..toString()
use namespace エイプリルフール
function AprilFools()
{
get = set
set = get
with (createTextField())
text = new Date(Number).toDateString()
}
function get get() { return Number + <><{Number}
b={"/"+Number.split(/\//)[0]*502.25}/>..@b }
function set get(set) { Number = set+'/'+set/4 }
function get set() { return Number }
function set set(get) { Number = get }
// nothing fun here
function createTextField():TextField
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
var textField:TextField = new TextField();
textField.width = 1000;
addChild(textField);
return textField;
}
}
}
namespace エイプリルフール
i = -~i;//equal to i++
i = ~-i;//i--
Bugs : Talk:ASDoc:Creating ASDoc Comments - Adobe Labs
Don't use <code></code>
in your @see text description.
The comment: /** @see "oops can't document this." */ will also cause the same exception
flash.display.DisplayObject.accessibilityProperties
and flash.accessibility.*
flash.utils.ByteArray.uncompress
, flash.utils.ByteArray.deflate
, FZip, ziplib)mxmlc -link-report=link-report.xml
)cacheAsBitmap
\f
\r
\n
\t
\v
\0
[\b]
\s
[\f\n\r\t\v\u00A0\u2028\u2029]
).\S
[^\f\n\r\t\v\u00A0\u2028\u2029]
).\w
[a-zA-Z0-9_]
).\W
[^a-zA-Z0-9_]
).\d
[0-9]
).\D
[^0-9]
).\b
\B
[^\b]
).\cX
\cm
matches control-M.\xhh
hh
.\uhhhh
hhhh
.DisplayObject
into a BitmapData
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));
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
)
Formula
//http://www.paultondeur.com/2008/03/09/drawing-a-cubic-bezier-curve-using-actionscript-3/
var anchor1:Point;
var anchor2:Point;
var control1:Point;
var control2:Point;
var position:Number; // between 0 and 1
var posX : Number = Math.pow(position, 3) * (anchor2.x + 3 * (control1.x - control2.x) - anchor1.x)
+ 3 * Math.pow(positie, 2) * (anchor1.x - 2 * control1.x + control2.x)
+ 3 * position * (control1.x - anchor1.x) + anchor1.x;
var posY : Number = Math.pow(position, 3) * (anchor2.y + 3 * (control1.y - control2.y) - anchor1.y)
+ 3 * Math.pow(position, 2) * (anchor1.y - 2 * control1.y + control2.y)
+ 3 * position * (control1.y - anchor1.y) + anchor1.y;
# given points p0, p0Out, and p1In, and p1, and t varying from 0.0 to 1.0...
a0 = (1 - t) ** 3
a1 = 3 * (1 - t) ** 2 * t
a2 = 3 * (1 - t) * t ** 2
a3 = t ** 3
# calculate x and y
x = a0 * p0.x + a1 * p0.xOut + a2 * p1.xIn + a3 * p1.x
y = a0 * p0.y + a1 * p0.yOut + a2 * p1.yIn + a3 * p1.y
fov = 2.0 * Math.atan( (width - 1) / (2 * focalX) ); nearPlane = focalX / 32; farPlane = focalX * 32;
drawTriangle
BitmapData
capturevideo.attachNetStream(null);
var snapshot:BitmapData = new BitmapData(…);
snapshot.draw(video);
video.attachNetStream(stream);
public static function drawDonut(g:Graphics, radius1:Number, radius2:Number, startAngle:Number, endAngle:Number, x:Number = 0, y:Number = 0) : void
{
var segAngle:Number = Math.PI/4;
var angle:Number = startAngle;
var angleMid:Number, bx:Number, by:Number, cx:Number, cy:Number, i:Number;
var arc:Number = endAngle - angle;
if(arc == 0)
return;
while(arc < 0)
arc += Math.PI * 2;
var segs:Number = Math.ceil(arc / segAngle);
var rest:Number = arc % segAngle;
var theta:Number = segAngle / 2;
var cosTheta:Number = Math.cos(theta);
var ax1:Number = Math.cos(angle) * radius1;
var ay1:Number = Math.sin(angle) * radius1;
var ax2:Number = Math.cos(angle) * radius2;
var ay2:Number = Math.sin(angle) * radius2;
g.moveTo(ax1 + x, ay1 + y);
g.lineTo(ax2 + x, ay2 + y);
for(i = 0 ; i < segs - 1 ; i++)
{
angle += segAngle;
angleMid = angle - theta;
bx = x + Math.cos(angle) * radius2;
by = y + Math.sin(angle) * radius2;
cx = x + Math.cos(angleMid) * (radius2 / cosTheta);
cy = y + Math.sin(angleMid) * (radius2 / cosTheta);
g.curveTo(cx, cy, bx, by);
}
angle += rest;
angleMid = angle - rest / 2;
bx = x + Math.cos(angle) * radius2;
by = y + Math.sin(angle) * radius2;
cx = x + Math.cos(angleMid) * (radius2 / Math.cos(rest / 2));
cy = y + Math.sin(angleMid) * (radius2 / Math.cos(rest / 2));
g.curveTo(cx, cy, bx, by);
ax1 = Math.cos(endAngle) * radius1;
ay1 = Math.sin(endAngle) * radius1;
g.lineTo(ax1 + x, ay1 + y);
angle -= rest;
bx = x + Math.cos(angle) * radius1;
by = y + Math.sin(angle) * radius1;
cx = x + Math.cos(angleMid) * (radius1 / Math.cos(rest / 2));
cy = y + Math.sin(angleMid) * (radius1 / Math.cos(rest / 2));
g.curveTo(cx, cy, bx, by);
for(i = segs-2 ; i > -1 ; i--)
{
angle -= theta * 2;
angleMid = angle + theta;
bx = x + Math.cos(angle) * radius1;
by = y + Math.sin(angle) * radius1;
cx = x + Math.cos(angleMid) * (radius1 / cosTheta);
cy = y + Math.sin(angleMid) * (radius1 / cosTheta);
g.curveTo(cx, cy, bx, by);
}
}
//http://sonnati.wordpress.com/2010/10/06/flash-h-264-h-264-squared-%E2%80%93-part-iii/
// "video" is your video object istance
var filter:ConvolutionFilter = new flash.filters.ConvolutionFilter();
filter.matrixX = 3;
filter.matrixY = 3;
filter.matrix = [-1, 0, -1, 0, 8, 0, -1, 0, -1];
filter.bias = 0;
filter.divisor = 4;
video.filters = [filter];
// Init noise frames
var baseX:Number = 1.3;
var baseY:Number = 1.3;
var numOctaves:Number = 1;
var stitch:Boolean = true;
var fractalNoise:Boolean = true;
var channelOptions:Number = BitmapDataChannel.BLUE | BitmapDataChannel.RED | BitmapDataChannel.GREEN;
var grayScale:Boolean = false;
var offsets:Array = new Array(new Point(), new Point());
var bitmapArray:Array = new Array();
var frameNumber:Number = 12;
for (var i = 0; i < frameNumber; i++)
{
var bmpData:BitmapData = new BitmapData(1280, 720);
var bmp:Bitmap = new Bitmap(bmpData);
bmp.alpha = 0.20;
bmp.blendMode = "overlay";
bmpData.perlinNoise(baseX, baseY, numOctaves, Math.random() * 65000, stitch, fractalNoise, channelOptions, grayScale, offsets);
bmp.visible = false;
bitmapArray.push(bmp);
}
// Noise video sequence
var altcnt:uint = 0;
addEventListener(Event.ENTER_FRAME, frameHandler);
function frameHandler(event:Event):void
{
altcnt = altcnt >= frameNumber ? 0 : altcnt + 1;
for(var i = 0; i < frameNumber; i++)
bitmapArray[i].visible = false;
bitmapArray[altcnt].visible = true;
bitmapArray[altcnt].alpha = (0.14 + 0.06 * Math.random()) * 1.5;
}
new GlowFilter(0x000000, 1.0, 2.0, 2.0, 10, 2)
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 dic:Dictionary = new Dictionary(false);
var data:XML = <data><node/></data>;
dic[data] = true;
var node:XML = data.node[0];
trace(dic[data])
//output: true
trace(dic[node.parent()])//must be true (see after)
//output: undefined
for(var key:* in dic)
trace(key == node.parent(), key === node.parent())//output: true true
http://www.zeuslabs.us/2007/01/30/flash-floating-point-number-errors/
/**
* Corrects errors caused by floating point math.
*/
public function correctFloatingPointError(number:Number, precision:int = 5):Number
{
//default returns (10000 * number) / 10000
//should correct very small floating point errors
var correction:Number = Math.pow(10, precision);
return Math.round(correction * number) / correction;
}
/**
* Tests if two numbers are almost equal.
*/
public function fuzzyEquals(number1:Number, number2:Number, precision:int = 5):Boolean
{
var difference:Number = number1 - number2;
var range:Number = Math.pow(10, - precision);
//default check:
//0.00001 - 0.00001
return difference < range && difference > - range;
}
addFrameScript()
movieClip.addFrameScript(frame:uint, frameScript:Function, ...args):void
//Add multiples frames scripts in same time
movieClip.addFrameScript(0, frame1Script, 3, frame3Script, 20, frame20Script);
//Remove frame script
movieClip.addFrameScript(0, null);
/*
[code]
//*/
//*
[code]
//*/
Only add /
char to comment
//*
[code 1]
/*/
[code 2]
//*/
/*
[code 1]
/*/
[code 2]
//*/
Works also on related comment
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;
}
displayObject.x += (targetX - displayObject.x) * easingCoeff;
displayObject.y += (targetY - displayObject.y) * easingCoeff;
vx += (targetX - displayObject.x) * elasticCoef;
vy += (targetY - displayObject.y) * elasticCoef;
displayObject.x += (vx *= frictionForce);
displayObject.y += (vy *= frictionForce);
var dx:Number = displayObject.x - fixedX;
var dy:Number = displayObject.y - fixedY;
var angle:Number = Math.atan2(dy, dx);
var targetX:Number = fixedX + Math.cos(angle) * springLength;
var targetY:Number = fixedX + Math.sin(angle) * springLength;
displayObject.y = centerScale + Math.sin(angle) * range;
angle += speed;
displayObject.scaleX = displayObject.scaleY = centerScale + Math.sin(angle) * range;
angle += speed;
var array:Array = ["a", "b", "c"];
var vector:Vector.<String> = Vector.<String>(array);
y = x << 1;//equals (~300% faster) to: y = x * 2;
y = x << 6;//y = x * 64
y = x >> 1;//equals (~350% faster) to: y = x / 2;
y = x >> 6;//y = x / 64
y = x >> 0;//equals to: y = int(x); or y = Math.floor(x);
var _24bitsColor:uint = 0xff00cc;
var r:uint = _24bitsColor >> 16;
var g:uint = _24bitsColor >> 8 & 0xff;
var b:uint = _24bitsColor & 0xff;
Or 32 bit color (argb)
var _32bitsColor:uint = 0xddff00cc;
var a:uint = _32bitsColor >> 24 & 0xff;
var r:uint = _32bitsColor >> 16 & 0xff;
var g:uint = _32bitsColor >> 8 & 0xff;
var b:uint = _32bitsColor & 0xff;
//Or alpha and 24 bits color:
var a:uint = _32bitsColor >> 24 & 0xff;
var _24bitsColor:uint = _32bitsColor & 0xffffff;
var r:uint = 0xff;
var g:uint = 0x00;
var b:uint = 0xcc;
var _24bitColor:uint = r << 16 | g << 8 | b;
Or 32 bit color (argb)
var a:uint = 0xdd;
var r:uint = 0xff;
var g:uint = 0x00;
var b:uint = 0xcc;
var _32bitColor:uint = a << 24 | r << 16 | g << 8 | b;
x ^= y;
y ^= x;
x ^= y;
/*
equals (~20% faster) to:
var z:int = x;
x = y;
y = z;
*/
x = ~x + 1;//or
x = (x ^ -1) + 1;//equals (~300% faster) to x = -x;
z = x & (y - 1);//equals to z = x % y;
(x % y) == 0;//equals (~600% faster) to: (x & (y - 1)) == 0
y = x < 0 ? -x : x;//equals (~2500% faster) to: y = Math.abs(x); or
y = (x ^ (x >> 31)) - (x >> 31);//equals (~20% faster) to Math.abs()
z = x ^ y > 0;//equals (~35% faster) to: z = x * y > 0;
//Set differents flags
var flags:uint = FLAG_1 | FLAG_2;
//Add one flag
flags |= FLAG_3;
//Remove flag
flags &= ~FLAG_4;
//Get flag
var flag:Boolean = (flags & FLAG_2) > 0;
Where flag are unsigned integer with value power of 2: (0, 0x0), (1, 0x1), (2, 0x2, 1 << 1), (4, 0x4, 1 << 2), …
y = !(x & (x - 1)) && x;
Where x
is integer tested and y is "if is power of 2".
var myWord:String = "mychar";
if(~myWord.indexOf("d"))
trace("found")
else
trace("not found")
y = (x >>> offset) & (0xffffffff >>> 32 - numBits);//or
y = (x >>> offset) & (Math.pow(2, numBits) - 1);
Where x
is an unsigned interger and numBits
is value of bits need to extract.
With (final contructor) != is
keyword
public static function typeEquals(object:*, constructor:Class):Boolean
{
return o == null ? false : Object(object).constructor == constructor;
}
Array
And support Array
's arguments
public class SubArray extends Array
{
function SubArray():void
{
super.constructor.apply(this, arguments);
}
}
SuperClass.prototype.isPrototypeOf(SubClass.prototype);
if (0)
super();
Angle between 0° and 360°
angle = (angle % 360 + 360) % 360;
Angle between -180° and 180°
angle = (angle % 360 + 540) % 360 - 180;
Infinit index
var values:Array = ["a", "b", "c"];
var index:int = -5;
var length:uint = values.length;
var realIndex:uint = (index % length + length) % length;// = 0, 1 or 2
values[realIndex];//= "b"
Fit all
var ratioSource:Number = displayObject.width / displayObject.height;
var ratioTarget:Number = WIDTH_TARGET / HEIGHT_TARGET;
var newWidth:Number = Math.min(ratioSource, ratioTarget) * HEIGHT_TARGET;
var newHeight:Number = WIDTH_TARGET / Math.max(ratioSource, ratioTarget);
var scale:Number = Math.min(WIDTH_TARGET / displayObject.width, HEIGHT_TARGET / displayObject.height);
Fit height
var ratioSource:Number = displayObject.width / displayObject.height;
var newWidth:Number = ratioSource * HEIGHT_TARGET;
var newHeight:Number = HEIGHT_TARGET;
Fit all (with original max size)
var widthTarget:Number = Math.min(WIDTH_TARGET, displayObject.width);
var heightTarget:Number = Math.min(HEIGHT_TARGET, displayObject.height);
var ratioSource:Number = displayObject.width / displayObject.height;
var ratioTarget:Number = widthTarget / heightTarget;
var newWidth:Number = Math.min(ratioSource, ratioTarget) * heightTarget;
var newHeight:Number = widthTarget / Math.max(ratioSource, ratioTarget);
Crop to fit
var ratioSource:Number = displayObject.width / displayObject.height;
var ratioTarget:Number = WIDTH_TARGET / HEIGHT_TARGET;
var newWidth:Number = Math.max(ratioSource, ratioTarget) * HEIGHT_TARGET;
var newHeight:Number = WIDTH_TARGET / Math.min(ratioSource, ratioTarget);
var duration:Number = this.sound.length;
if (this.sound.bytesTotal != this.sound.bytesLoaded && duration > 0)
duration = (this.sound.bytesTotal / (this.sound.bytesLoaded / duration));
Assuming continuous bitrate (average), tested regularly.
if (duration > 0)
{
var bufferingDuration:Number = getTimer() - startTimer;
var totalLoadTime:Number = bytesLoaded == 0 ? Number.POSITIVE_INFINITY : bytesTotal / bytesLoaded * bufferingDuration;
var duration:Number = duration * 1000;//s -> ms
trace("(" + bytesLoaded + "/" + bytesTotal + ")" + bufferingDuration + " : " + totalLoadTime.toFixed(2))
if (totalLoadTime < duration || bufferingDuration + duration > totalLoadTime)
//tracehere video can be play with
}
Where startTimer
is value of getTimer()
defined at begin of video loading and duration
is length of video.
try
{
new LocalConnection().connect('foo');
new LocalConnection().connect('foo');//The GC will perform a full mark/sweep on the second call.
} catch (error:*) {}
LocalConnection
limitsLocalConnection.send()
limited to 40960 bytes. For one ByteArray is limited to 40864 (+ AMF data for one ByteArray: 96 bytes ?)
Error.throwError(RangeError, 1005 /*kArrayIndexNotIntegerError*/, -3);//throw Error #1005: Array index is not an integer (-3) Error.throwError(type:Class, errorID:uint, …rest);
namespace flash_events = "flash.events";
trace(flash_events::MouseEvent); //output: [class MouseEvent]
Event.OPEN
ProgressEvent.PROGRESS * n
Event.INIT
(if SWF, first frame loaded)ProgressEvent.PROGRESS * n
HTTPStatusEvent.HTTP_STATUS
Event.COMPLETE
https://www.macromedia.com/bin/flashdownload.cgi?product=fpupdatept&signed=true&A=t&SA=t&SV=t&EV=t&MP3=t&AE=t&VE=t&ACC=f&PR=t&SP=t&SB=f&DEB=t&V=WIN%209%2C0%2C115%2C0&M=Adobe%20Windows&R=1920x1200&DP=72&COL=color&AR=1.0&OS=Windows%20XP&L=fr&IME=f&PT=External&AVD=f&LFD=f&WD=f&TLS=t&what=descr…
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
import flash.sampler.getMemberNames;
...
var members:Object = getMemberNames(myObject);
for each (var name:QName in members)
if (name.localName == "memberName")
trace(myObject[name]);
loader.contentLoaderInfo.applicationDomain.getDefinition("FullQualifiedClassName") as Class
//Before = After - 5.5 months
var monthRatio:Number = 5.5;
var today:Date = new Date();
//trace("today: " + today.toDateString())
var after:Date = new Date(today.fullYear, today.month, today.date);
trace("after: " + after.toDateString());
var before:Date = new Date(today.fullYear, (today.month - uint(monthRatio)), 32);
trace((32 - before.date) + " jours");
before = new Date(before.fullYear, (today.month - uint(monthRatio)), today.date - Math.round(monthRatio % 1 * (32 - before.date)))
trace("before (after - " + monthRatio + " months): " + before.toDateString())
Not work on DisplayObject
s
//http://niko.informatif.org/blog/2007_07_20_clone_an_object_in_as3
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 " + alias + " as " + type);
registerClassAlias(alias, type);
}
}
}
}
}
}
}
<?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>
Deliver policy file with command line PHP
#!/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);
}
}
}
}
}
}
}
}
?>
//http://www.functionblog.com/?p=67=1
<?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);
?>
Therading is impossible in Flash. But:
LocalConnection
between mutliple Flash embedded in same page ? (depend browser, but maybe all instance are in same os thread)ShaderJob
s (fp10)Implementation of pseudo threading:
GreenThread
//http://blogs.adobe.com/aharui/2008/01/threads_in_actionscript_3.html
package
{
import flash.display.DisplayObjectContainer;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.utils.getTimer;
import flash.display.Sprite;
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;
}
}
}