Как бороться c утечками памяти при загрузке внешних swf-модулей рассказано в блоге Максима Фирсова:
http://snzflash.com/blog/?p=54
http://snzflash.com/blog/?p=54

/**
* Рисует check-текстуру
* @param canvas - экземпляр класса Graphics
* @param width - ширина требуемой текстуры
* @param height - высота требуемой текстуры
* @param cellSize - размер ячейки
* @param cellColors - массив с цветами для нечетной и четной ячеек в формате RGBA
* @param lineColor - цвет линии между ячейками в формате RGBA
*/
public function drawCheckFill(canvas:Graphics, width:Number, height:Number, cellSize:Number, cellColors:Array = null, lineColor:uint = 0x080808FF):void
{
var colors:Array = cellColors || [0x111111FF, 0x202020FF];
colors = colors.slice(0, 2);
var cols:int = int(width / cellSize);
var rows:int = int(height / cellSize);
var color:uint = 0;
for (var i:int = 0; i < cols; i++)
{
for (var j:int = 0; j < rows; j++)
{
color = colors[(i + j) % 2];
canvas.beginFill(color >> 8, (color & 0x000000FF) / 0xFF);
canvas.drawRect(i * cellSize, j * cellSize, cellSize, cellSize);
}
}
canvas.endFill();
canvas.lineStyle(1, lineColor >> 8, (lineColor & 0x000000FF) / 0xFF, true, LineScaleMode.NORMAL, CapsStyle.NONE);
for (i = 0; i < cols; i++)
{
canvas.moveTo(i * cellSize, 0);
canvas.lineTo(i * cellSize, rows * cellSize);
}
for (i = 0; i < rows; i++)
{
canvas.moveTo(0, i * cellSize);
canvas.lineTo(cols * cellSize, i * cellSize);
}
}
var shape:Shape = new Shape();
drawCheckFill(shape.graphics, 170, 170, 8, [0XFFFFFFFF, 0xCCCCCCFF], 0);
P.S.: Кстати для создания текстур для материалов 3D-движков тоже сгодится.
ping localhost -n <примерное время в секундах>
C:\Project>svn up & ant secureClient & ant
private function overlayOpacityMap(texture:BitmapData, opacityMap:BitmapData):BitmapData
{
if (!opacityMap)
return texture;
var retval:BitmapData = new BitmapData(texture.width, texture.height, true, 0xffffffff);
retval.copyPixels(texture, new Rectangle(0, 0, texture.width, texture.height), new Point());
var textureColor:uint;
var opacityColor:uint;
for (var px:int = 0; px < retval.width; px++)
{
for (var py:int = 0; py < retval.height; py++)
{
textureColor = retval.getPixel32(px, py);
opacityColor = opacityMap.getPixel(px, py);
opacityColor &= 0x0000ff;
textureColor &= 0x00ffffff;
textureColor |= (0xff - opacityColor) << 24;
retval.setPixel32(px, py, textureColor);
}
}
return retval;
}
В результате волшебных пассов результат получился достаточно достойным и фотореалистичным, жаль заказчик не понял всю "тяжесть, степень, глубину" и в финальной стадии разработки принял решение заменить 3D на секвенцию из 30, на мой взгляд, не лучшим образом отфотканных ракурсов.
public class TrustChecker
{
private var _stage:Stage;
public function TrustChecker(stage:Stage)
{
_stage = stage;
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onError);
loader.load(new URLRequest("http://myurl.com/trust.gif?" + (new Date().getTime())));
}
private function onError(e:Event):void
{
var target:LoaderInfo = e.target as LoaderInfo;
target.removeEventListener(Event.COMPLETE, onComplete);
target.removeEventListener(IOErrorEvent.IO_ERROR, onError);
}
private function onComplete(e:Event):void
{
var target:LoaderInfo = e.target as LoaderInfo;
target.removeEventListener(Event.COMPLETE, onComplete);
target.removeEventListener(IOErrorEvent.IO_ERROR, onError);
// вот тут то можно дать волю своей фантазии для донесения мысли заказчику
var shape:Shape = new Shape();
shape.graphics.beginFill(0x000000);
shape.graphics.drawRect(0, 0, _stage.stageWidth, _stage.stageHeight);
shape.graphics.endFill();
_stage.addChild(shape);
}
}
public class DateFormatter
{
private static const MAP_TOKENS:Object = new Object();
private static const DATE:Date = new Date();
/// метод форматирования №1
public static function formatDate(date:Date, pattern:String):String
{
DATE.setTime(date.getTime());
return format(DATE, pattern);
}
/// метод форматирования №2
public static function formatTimestamp(timestamp:Number, pattern:String):String
{
DATE.setTime(timestamp);
return format(DATE, pattern);
}
private static function format(date:Date, pattern:String):String
{
DATE.setTime(date.getTime());
var tokens:Array = [];
for (var token:String in MAP_TOKENS)
{
if (pattern.indexOf(token) != -1)
tokens.push(token);
}
var retval:String = pattern;
for each (token in tokens)
{
retval = retval.replace(token, (MAP_TOKENS[token] as Function).apply());
}
return retval;
}
private static function formatSeconds():String
{
return leadZero(DATE.getSeconds());
}
private static function formatMinutes():String
{
return leadZero(DATE.getMinutes());
}
private static function formatHours():String
{
return leadZero(DATE.getHours());
}
private static function formatFullYear():String
{
return leadZero(DATE.getFullYear());
}
private static function formatDay():String
{
return leadZero(DATE.getDate());
}
private static function formatMonth():String
{
var month:int = DATE.getMonth() + 1;
return leadZero(month);
}
private static function leadZero(value:int):String
{
return (value < 10 ? "0" : "") + value.toString();
}
// блок статической инициализации
{
MAP_TOKENS["MM"] = formatMonth;
MAP_TOKENS["DD"] = formatDay;
MAP_TOKENS["YYYY"] = formatFullYear;
MAP_TOKENS["hh"] = formatHours;
MAP_TOKENS["mm"] = formatMinutes;
MAP_TOKENS["ss"] = formatMinutes;
}
}
Пример использования:
var sysdate:Date = new Date();
trace(DateFormatter.formatDate(sysdate, "DD.MM.YYYY"); // 21.02.2011
trace(DateFormatter.formatDate(sysdate, "MM/DD/YYYY"); // 02/21/2011
trace(DateFormatter.formatDate(sysdate, "MM/DD/YYYY hh:mm:ss"); // 02/21/2011 14:26:01
trace(DateFormatter.formatDate("hh:mm:ss"); // 14:26:01
// или так можно, но только осторожно
trace(DateFormatter.formatDate("Today is DD.MM.YYYY"); // Today is 21.02.2011
Необходимые для конкретного языка шаблоны форматирования хранятся в соответствующих файлах. Вытягивать и хранить это все можно способом описанным в этом посте.
Например:
Arial bg_en BTN_ACCEPT;BTN_OK;BTN_CANCEL BTN_BUY;BTN_CANCEL
const DEFAULT_LANG:String = "ru";
LocaleSettings.setDefaultLang(DEFAULT_LANG);
LocaleSettings.addXMLPath(DEFAULT_LANG, "settings/set_" + DEFAULT_LANG + ".xml"); // связываем язык с путем xml-файла
var language:String = (loaderInfo.parameters.lang ? loaderInfo.parameters.lang : DEFAULT_LANG);
LocaleSettings.addXMLPath(language, "settings/set_" + language + ".xml");
LocaleSettings.loadSettingsXML(language, languageXMLLoaded); // запускаем загрузку файла с настройками
...
private function languageXMLLoaded(success:Boolean):void
{
if (LocaleSettings.checkXMLStatus())
{
// пользуем загруженные настройки
mainScreen.setBg(LocaleSettings.loadSetting("client", "bg_frame_label");
}
}
package
{
import flash.display.*;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.net.*;
import flash.utils.*;
public class VideoMJPEG extends Sprite
{
private var _stream:URLStream = new URLStream();
private var _loader:Loader = new Loader()
private var _buffer:ByteArray;
private var _write:Boolean = false;
private var _markerDetection:Boolean = false;
private var _request:URLRequest = new URLRequest("http://146.176.65.10/axis-cgi/mjpg/video.cgi");
public function VideoMJPEG()
{
mouseEnabled = false;
mouseChildren = false;
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
private function onAddedToStage(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
addChild(_loader);
_stream.load(_request);
_stream.addEventListener(ProgressEvent.PROGRESS, onProgress);
}
private function onProgress(event:ProgressEvent):void
{
var byte:int;
// Если есть доступные байты - обработать их
while(_stream.bytesAvailable > 0)
{
byte = _stream.readUnsignedByte();
if(_write) _buffer.writeByte(byte);
if(_markerDetection)
{
switch(byte)
{
case 0xD8:
_write = true;
_buffer = new ByteArray();
_buffer.writeByte(0xFF);
_buffer.writeByte(0xD8);
break;
case 0xD9:
_write = false;
_buffer.writeByte(0xD9);
_loader.loadBytes(_buffer);
break;
}
}
_markerDetection = (byte == 0xFF);
}
}
}
}

public class AppOption
{
public static const REVISION:String = "@revision@";
}
<target name="buildClient">
<!-- копируем оригинал файла где будет производится замена строки -->
<copy file="${src}/AppOption.as" tofile="${projectDir}/AppOption.as" overwrite="true" verbose="false" />
<!-- впечатываем номер ревизии по-вкусу, в данном случае последней закомиченой-->
<property name="revision" value="COMMITTED"/>
<exec executable="svn" outputproperty="svnlog.out">
<arg line="log -r ${revision} -q"/>
</exec>
<taskdef resource="net/sf/antcontrib/antcontrib.properties"/>
<propertyregex property="revision.number" input="${svnlog.out}" select="\2">
<regexp pattern="(r)([0-9]*)"/>
</propertyregex>
<replace file="${src}/AppOption.as" token="@revision@" value="${revision.number}"/>
<!-- компилируем клиента -->
<!-- перемещаем оригинал файла на родину -->
<move file="${projectDir}/AppOption.as" tofile="${src}/AppOption.as" overwrite="true" verbose="false"/>
</target>
public class Main extends Sprite
{
private var _contextMenu:ContextMenu;
public Main()
{
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
private function onAddedToStage(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
_contextMenu = new ContextMenu();
var menuItem:ContextMenuItem = new ContextMenuItem("Version " + AppOption.REVISION);
_contextMenu.customItems.push(menuItem);
contextMenu = _contextMenu;
}
}
function removeAllChilds(container:DisplayObjectContainer):void
{
while (container.numChildren)
{
container.removeChildAt(0);
}
}
public interface IDisposable
{
function dispose():void;
}
function removeAllChilds(container:DisplayObjectContainer):void
{
var removableObject:DisplayObject;
while (container.numChildren)
{
removableObject = container.removeChildAt(0);
if (removableObject is IDisposable)
(removableObject as IDisposable).dispose();
}
}
function getClassRef(instance:Object):Class
{
return getDefinitionByName(getQualifiedClassName(instance)) as Class;
}
function getClassRef(instance:Object):Class
{
return Object(instance).constructor as Class;
}
function polymorphAction(instance:Object):void
{
var clazz:Class = Object(instance).constructor as Class;
switch (clazz)
{
case Friend:
trace("друг");
break;
case Enemy:
trace("враг");
break;
default:
trace("а так");
}
}