Thursday, September 18, 2025

Mitch still has blog

Help ik heb een hulpverlener.

Dat is de titel van het boek dat mijn advocaat altijd al eens had willen schrijven. Ikzelf overwoog een aantal andere titels. Er is niks wat je kunt zeggen. Alles is al gezegd. En er hoeft niks meer gezegd te worden.

Woorden schieten tekort om uit te leggen wat ik heb meegemaakt. Toch schrijf ik deze blog.

Op dit moment zit ik in mijn eigen tuin bij mijn eigen huis, overgoten met zonneschijn en de aarde draait nog steeds rondjes, maar dat is sinds het begin al zo. Alles komt goed. Ik zit hier welliswaar nog steeds zonder mijn kinderen. Maar het laatste liedje is nog niet gezongen.

Help ik heb een hulpverlener. Ik dacht eerst dat hij doelde op mijn ex-partner die in de zorg werkt. Toen dacht ik dat hij doelt op de leuke meisjes van Veilig Thuis. Toen dacht ik geheime diensten. Of toch de RvdK. Of toch maar weer zorgverlening van mondriaan. Ik moet het hem nog eens vragen onder het genot van een kopje koffie of dertig. Ik heb in elk geval een psychopatisch verhaal te vertellen waar je schoenen van uit vallen.

Het begon allemaal... weet ik veel. We hebben een gelukkig leventje gehad, samen, mijn ex en ik, voor zo'n 7 jaar. En twee engeltjes geproduceert. Na een turbulente tijd waarin kanker en schedelfacturen de boventoon voerde was ik uitgeput. En mijn ex ook. Toen blufte ze een jaar lang met een scheiding. Waar ik krankzinnig van werd. Totdat ik die bluf call'de. Dit was in april 2024. Ze had vaker moeten meedoen met pokeren om te snappen hoe ik in elkaar zit. En ik had eerder hulp moeten vragen aan hulpverlening om me te helpen begrijpen hoe een hulpverlener in elkaar zit. Lang verhaal kort. We zijn gescheiden in juni 2024. We hebben enigszins redelijk co-ouderschap volgehouden voor een aantal maanden. Ik was niet stabiel. Zij ogenschijnlijk wel. Ik heb harde uitspraken gedaan. Zoals de wens dat iemand eindelijk eens die plank voor haar kop zou moeten doorzagen. Dat zou je kunnen zien als doodsbedreiging met wat creativiteit. Zij deed daarintegen, uh, ja, géén uitspraken. Zij was ogenschijnlijk het angstige slachtoffer. De climax van ons conflict was een contactverbod dat de politie me kwam brengen met de man-tot-man boodschap erbij dat het waarschijnlijk precies is wat ik nodig heb. Alleen zag ik dat zelf niet zo. En de waarschuwing dat het contactverbod éénrichting is. En oeps. Jawel. Ze belde me om te flirten na al mijn vermeende bedreigingen. Dat zegt veel. Ik ging er niet op in. Paar dagen later belde ik haar in verband met een tandarts afspraak. Ze hing hypocriet de telefoon op nog voordat ik een woord had uitgesproken. Ik verloor mijn geduld. En ben op haar deur gaan bonken. Het raam brak. En het contactverbod dus ook. Oeps.

De politie plukte me van de straat en ik werd drie nachten in voorlopige hechtenis geflikkert. Het was even spannend of ik hier twee weken voor moest gaan brommen of niet. Ik heb een agente ter plaatse gesommeerd om mijn ex te sommeren om mijn dochter op tijd van school te halen. Ik was immers eventjes verhindert. Op de binnenkant van de celdeur waren leuzen te lezen van mijn voorgangers. Dingen als "kankerhoer" en "kankerwout". Ik gooide het over een andere boeg en troostte mijzelf  en mijn opvolgers door mijn broek uit te doen en met mijn gulp levensgroot op de binnenkart van mijn celdeur te krassen "ALLES KOMT GOED". Verder heb ik mezelf vermaakt door kinderliedjes te zingen in de zwaarste stem die ik op kon zetten totdat ik hees was. Gelukkig kwam ik inderdaad vrij onder voorwaarde dat ik meldplicht heb bij reclassering en mij niet in de straat bevindt. Beetje dom, want toen ze mij in de cel flikkerde hebben ze haar en mijn kids in een blijf-van-mijn-lijf huis geflikkert. Dit was in januari 2025. Sindsdien heb ik mijn kinderen een 9 maanden niet meer gezien. Wát een bevalling zeg! Wordt vervolgd.

Monday, March 14, 2011

AS3 Smooth movement

When the display list changes with a TimerEvent, call event.updateAfterEvent() to update the screen immediately.

Use getTimer() when you are crunching numbers relative to time. Do not rely on Timer.delay.



updateAfterEvent()

In the event handler of TimerEvent.TIMER, you can use event.updateAfterEvent() which updates the display list after the event is processed. Smaller values for the timer's delay, means more screen updates.
This way, Flash Player doesn't have to wait for the next "frame". And things like movement will look smoother.

For example:

private function timerEventHandler(event:TimerEvent):void
{
player1.x += horizontalVelocity;
player1.y += verticalVelocity; event.updateAfterEvent();
}



getTimer()

You can specify the delay of a Timer. But Flash Player can't promise to update after exáctly the specified delay. To be more accurate, you can keep track of how much time really passed using getTimer(). And adjust your variables accordingly.

For example:

var elapsedTime:int;
var time:int;
private function timerEventHandler(event:TimerEvent):void
{
var currentTime:int = getTimer();
elapsedTime = currentTime - time;
time = currentTime;
var f:Number = elapsedTime / timer.delay;
player1.x += horizontalVelocity * f;
player1.y += verticalVelocity * f;
event.updateAfterEvent();
}

Tuesday, February 22, 2011

AS3 Effect Fly

The Fly effect launches an object into the air.
Define properties velocity and degrees/radians.
You can define fromX and fromY (target's position by default).
You can also apply gravity and/or friction.
Define friction through properties frictionVelocity and frictionDegrees/frictionRadians.
You can change the speed/precision of the animation using property frameRate.
Property bounds is necessary to end the animation. Property bounds has a default value that is usually outside of the screen.


mitch/effects/Fly.as

package mitch.effects
{
import flash.geom.Rectangle;

import mitch.effects.effectClasses.FlyInstance;

import mx.effects.IEffectInstance;

import spark.effects.Animate;

/**
* The Fly effect extends the Animate effect.
* Though, property <code>motionPaths</code> is created dynamically on the effect instance.
*
* @see mitch.effects.effectClasses.FlyInstance
*
* @author Mitch
*
*/

public class Fly extends Animate
{

//------------------------------------------------------------
//
// Static Members
//
//------------------------------------------------------------

/**@private */
private static const PI2:Number = Math.PI * 2;

//------------------------------
// getRadians()
//------------------------------

/**
* Converts degrees to radians.
* @param degrees Angle in degrees
* @return Angle in radians.
*
*/

static public function getRadians(degrees:Number):Number {
return normalizeRadians(degrees * Math.PI / 180);
}

//------------------------------
// getDegrees()
//------------------------------

/**
* Converts radians to degrees.
* @param radians Angle in radians.
* @return Angle in degrees.
*
*/

static public function getDegrees(radians:Number):Number {
return normalizeDegrees(radians * 180 / Math.PI);
}

//------------------------------
// normalizeDegrees()
//------------------------------

/**
* Returns a value between 0 and 360. <br/>
* For example; if parameter <code>degrees</code> is set to 450, the return value would be 90.
* @param degrees The anngle to normalize.
* @return The specified angle, normalized between 0 and 360.
*/

static public function normalizeDegrees(degrees:Number):Number {
while(degrees > 360) {
degrees -= 360;
}
while(degrees < 0) {
degrees += 360;
}
return degrees;
}

//------------------------------
// normalizeRadians()
//------------------------------

/**
* Returns a value between <code>(Math.PI * -2)</code> and <code>(Math.PI * 2)</code>.
* @param radians The angle to normalize.
* @return The specified angle, normalized between <code>Math.PI * -2</code> and <code>Math.PI * 2</code>.
*/

static public function normalizeRadians(radians:Number):Number {
while (radians >= PI2 )
{
radians -= PI2;
}
while (radians < -PI2 )
{
radians += PI2;
}
return radians;
}




/**
* @private
* Storage for property degrees/radians.
*/

private var _degrees:Number = 0;
/**
* @private
* Storage for property frictionDegrees/fricitonRadians.
*/

private var _frictionDegrees:Number = 0;

//------------------------------------------------------------
//
// Constructor
//
//------------------------------------------------------------

/**
* Constructor.
*
* @param target The component to animate with this effect.
*
*/

public function Fly(target:Object=null)
{
super(target);
easer = null;
instanceClass = FlyInstance;
}




//------------------------------------------------------------
//
// Public Properties
//
//------------------------------------------------------------

//------------------------------
// fromX
//------------------------------

/**
* The initial x coördinate, in pixels.
*/

public var fromX:Number = NaN;

//------------------------------
// fromY
//------------------------------

/**
* The initial y coördinate, in pixels.
*/

public var fromY:Number = NaN;

//------------------------------
// gravity
//------------------------------

/**
* The amount gravity to apply, in pixels per frame.
*/

public var gravity:Number = 1;

//------------------------------
// velocity
//------------------------------

/**
* The initial velocity, in pixels per frame.
*/

public var velocity:Number = 25;

//------------------------------
// radians
//------------------------------

/**
* The initial angle, in radians.
*/

public function get radians():Number { return degrees * Math.PI / 180; }
/**@private */
public function set radians(value:Number):void {
degrees = getDegrees(value);
}

//------------------------------
// degrees
//------------------------------

/**
* The initial angle, in degrees.
*/

public function get degrees():Number { return _degrees; }
/**@private */
public function set degrees(value:Number):void {
_degrees = normalizeDegrees(value);
}


//------------------------------
// frictionRadians
//------------------------------

/**
* The friction angle, in radians.
*/

public function get frictionRadians():Number { return frictionDegrees * Math.PI / 180; }
/**@private */
public function set frictionRadians(value:Number):void {
frictionDegrees = getDegrees(value);
}

//------------------------------
// frictionDegrees
//------------------------------

/**
* The friction angle, in degrees.
*/

public function get frictionDegrees():Number { return _frictionDegrees; }
/**@private */
public function set frictionDegrees(value:Number):void {
_frictionDegrees = normalizeDegrees(value);
}


//------------------------------
// frictionVelocity
//------------------------------

/**
* The friction velocity, in pixels per frame.
*/

public var frictionVelocity:Number = 0;

//------------------------------
// bounds
//------------------------------

/**
* The minimum and maximum values for properties <code>x</code> and <code>y</code> in this effect.
* The effect ends when the x and y coördinates exceed the rectangular region defined by this property.
*/

public var bounds:Rectangle = new Rectangle(-1000, -1000, 3000, 3000);

//------------------------------
// frameRate
//------------------------------

/**
* The effect speed, in frames per second.
* <p>Larger values cause the effect to play faster. Smaller values cause the effect to play slower.</p>
*/

public var frameRate:uint = 30;






//------------------------------------------------------------
//
// Overridden Methods
//
//------------------------------------------------------------

//------------------------------
// initInstance()
//------------------------------

/**
* @copy spark.effects.Animate#initInstance()
*/

protected override function initInstance(instance:IEffectInstance):void
{
//set motionPaths before initializing.
var inst:FlyInstance = FlyInstance(instance);
inst.fromX = fromX;
inst.fromY = fromY;
inst.bounds = bounds;
inst.degrees = degrees;
inst.frameRate = frameRate;
inst.frictionDegrees = frictionDegrees;
inst.frictionVelocity = frictionVelocity;
inst.gravity = gravity;
inst.velocity = velocity;
super.initInstance(instance);
}

}
}



The FlyInstance class sets it's own motionPaths property in method play().
Rotation is handled in overridden method animationUpdate().

mitch/effects/effectClasses/FlyInstance.as

package mitch.effects.effectClasses
{
import flash.geom.Rectangle;

import mitch.effects.Fly;

import spark.effects.animation.Animation;
import spark.effects.animation.Keyframe;
import spark.effects.animation.MotionPath;
import spark.effects.supportClasses.AnimateInstance;

/**
* The FlyInstance class implements the instance class for the Fly effect.
* Flex creates an instance of this class when it plays a Fly effect; you do not create one yourself.
*
* @see mitch.effects.Fly
*
* @author Mitch
*
*/

public class FlyInstance extends AnimateInstance
{
/**
* @private
* Storage for the current x coordinate. Updates when the effect updates.
*/

private var _currentX:Number = NaN;
/**
* @private
* Storage for the current y coordinate. Updates when the effect updates.
*/

private var _currentY:Number = NaN;
/**
* @private
* Storage for property degrees/radians.
*/

private var _degrees:Number = 0;
/**
* @private
* Storage for property frictionDegrees/frictionRadians.
*/

private var _frictionDegrees:Number = 0;




//------------------------------------------------------------
//
// Constructor
//
//------------------------------------------------------------

/**
* Constructor.
* @param target The component to animate with this effect.
*
*/

public function FlyInstance(target:Object)
{
super(target);
}




//------------------------------------------------------------
//
// Public Properties
//
//------------------------------------------------------------

//------------------------------
// fromX
//------------------------------

/**
* @copy mitch.effects.Fly#fromX
*/

public var fromX:Number;

//------------------------------
// fromY
//------------------------------

/**
* @copy mitch.effects.Fly#fromY
*/

public var fromY:Number;

//------------------------------
// gravity
//------------------------------

/**
* @copy mitch.effects.Fly#gravity
*/

public var gravity:Number;

//------------------------------
// velocity
//------------------------------

/**
* @copy mitch.effects.Fly#velocity
*/

public var velocity:Number;

//------------------------------
// radians
//------------------------------

/**
* @copy mitch.effects.Fly#radians
*/

public function get radians():Number { return degrees * Math.PI / 180; }
/**@private */
public function set radians(value:Number):void {
degrees = Fly.getDegrees(value);
}

//------------------------------
// degrees
//------------------------------

/**
* @copy mitch.effects.Fly#degrees
*/

public function get degrees():Number { return _degrees; }
/**@private */
public function set degrees(value:Number):void {
_degrees = Fly.normalizeDegrees(value);
}


//------------------------------
// frictionRadians
//------------------------------

/**
* @copy mitch.effects.Fly#frictionRadians
*/

public function get frictionRadians():Number { return frictionDegrees * Math.PI / 180; }
/**@private */
public function set frictionRadians(value:Number):void {
frictionDegrees = Fly.getDegrees(value);
}

//------------------------------
// frictionDegrees
//------------------------------

/**
* @copy mitch.effects.Fly#frictionDegrees
*/

public function get frictionDegrees():Number { return _frictionDegrees; }
/**@private */
public function set frictionDegrees(value:Number):void {
_frictionDegrees = Fly.normalizeDegrees(value);
}


//------------------------------
// frictionVelocity
//------------------------------

/**
* @copy mitch.effects.Fly#frictionVelocity
*/

public var frictionVelocity:Number;

//------------------------------
// bounds
//------------------------------

/**
* @copy mitch.effects.Fly#bounds
*/

public var bounds:Rectangle;

//------------------------------
// frameRate
//------------------------------

/**
* @copy mitch.effects.Fly#frameRate
*/

public var frameRate:uint;




//------------------------------------------------------------
//
// Public Methods
//
//------------------------------------------------------------

//------------------------------
// play()
//------------------------------

/**@copy spark.effects.supportClasses.AnimateInstance#play() */
public override function play():void
{
createMotionPaths();
super.play();
}

//------------------------------
// createMotionPaths()
//------------------------------

/**
* Creates a Vector containing a MotionPath object for each of the properties
* <code>x</code>, <code>y</code> and <code>rotation</code>.
* And sets property <code>motionPaths</code> to that vector.
*
*/

public function createMotionPaths():void
{
//Vector containing MotionPaths
var result :Vector.<MotionPath> = new Vector.<MotionPath>(2, true);

//x
result[0] = new MotionPath("x");
result[0].keyframes = new Vector.<Keyframe>();
//y
result[1] = new MotionPath("y");
result[1].keyframes = new Vector.<Keyframe>();

//Numbers
var time :Number = 0;
var delay :Number = 1000 / frameRate;
var xcurrent :Number = isNaN(fromX)==false?fromX:(target?target.x:0);
var ycurrent :Number = isNaN(fromY)==false?fromY:(target?target.y:0);
var xvelocity :Number = Math.cos(radians) * velocity;
var yvelocity :Number = Math.sin(radians) * velocity;
var xfriction :Number = Math.cos(frictionRadians) * frictionVelocity;
var yfriction :Number = Math.sin(frictionRadians) * frictionVelocity;
var rcurrent :Number = getRotation(xvelocity + xfriction, yvelocity + yfriction);
//add first keyframes
var xframes:Vector.<Keyframe> = result[0].keyframes;
var yframes:Vector.<Keyframe> = result[1].keyframes;
result[0].keyframes.push(new Keyframe(time, xcurrent));
result[1].keyframes.push(new Keyframe(time, ycurrent));


//while not out of bounds
while(bounds.contains(xcurrent, ycurrent))
{
//adjust time
time += delay;

//add gravity to velocity
yvelocity += gravity;

//add friction to velocity
if(Math.round(rcurrent) < frictionDegrees + 90 -1 || Math.round(rcurrent) > frictionDegrees + 90 + 1) {
xvelocity += xfriction;
yvelocity += yfriction;
}
//apply velocity
xcurrent += xvelocity;
ycurrent += yvelocity;
//apply rotation
rcurrent = getRotation(xvelocity, yvelocity);
//save keyframes
result[0].keyframes.push(new Keyframe(time, xcurrent));
result[1].keyframes.push(new Keyframe(time, ycurrent));
}
super.motionPaths = result;
}

//------------------------------
// animationUpdate()
//------------------------------

/**@copy spark.effects.supportClasses.AnimateInstance#animationUpdate() */
public override function animationUpdate(animation:Animation):void
{
if(isNaN(_currentX)) {
_currentX = animation.currentValue.x;
}
if(isNaN(_currentY)) {
_currentY = animation.currentValue.y;
}
var xv:Number = Number(animation.currentValue.x) - _currentX;
var yv:Number = Number(animation.currentValue.y) - _currentY;
_currentX = Number(animation.currentValue.x);
_currentY = Number(animation.currentValue.y);

// Update the rotation during animation.
// Instead of using MotionPath
// and relying on the effect framework.
target.rotation = getRotation(xv, yv);

super.animationUpdate(animation);
}

//------------------------------
// animationEnd()
//------------------------------

/**@copy spark.effects.supportClasses.AnimateInstance#animationEnd() */
public override function animationEnd(animation:Animation):void
{
_currentX = NaN;
_currentY = NaN;
super.animationEnd(animation);
}

//------------------------------------------------------------
//
// Protected Methods
//
//------------------------------------------------------------

//------------------------------
// getRotation()
//------------------------------

/**
* Calculates the rotation in degrees, using the specified point.
* <p>The x and y coördinates can be interpreted as a Vector,
* assuming that the second point is <code>(0, 0)</code>. And an angle can be extracted from the Vector.</p>
* @param x The x coördinate to use for calculating the angle.
* @param y The y coördinate to use for caluclating the angle.
* @return The angle in degrees, calculated using the x and y coördinates.
*
*/

protected function getRotation(x:Number, y:Number):Number
{
//calculate degrees
var result:Number = Math.atan(y/x) * 180 / Math.PI;
if(x < 0) {
result -= 180;
}
return Fly.normalizeDegrees(result);
}
}
}

Saturday, February 5, 2011

AS3 Class SmartMask

The SmartMask class is used to create a complex shaped mask.

Define properties maskWidth and maskHeight to draw a rectangle on this object. Then, cut shapes from the rectangle using method addSilhouet(). Undo the cutting by calling removeSilhouet().

These methods require a BitmapData object as parameter. You could use method getSilhouetData() to create that BitmapData object.



mitch/components/SmartMask.as

package mitch.components
{
import flash.display.Bitmap;

import flash.display.BitmapData;
import flash.display.DisplayObject;
import flash.events.Event;

import flash.geom.ColorTransform;
import flash.geom.Point;

import mx.core.UIComponent;


/**
* <p>The SmartMask class is used to create a complex shaped mask.</p>
*
* <p>Define properties <code>maskWidth</code> and <code>maskHeight</code>

* to draw a rectangle on this object. Then, cut shapes from the rectangle
* using method <code>addSilhouet()</code>. Undo the cutting by calling
* <code>removeSilhouet()</code>. These methods require a BitmapData object
* as parameter. You could use method <code>getSilhouetData()</code>
* to create that BitmapData object.</p>

*
* @author Mitch
*
*/

public class SmartMask extends UIComponent
{
/**
* @private
* Results in a color, other than blue.
*/

private static const NOT_BLUE:ColorTransform = new ColorTransform(

1, 0, 0, 1, 255, 0, 0, 255);

/**
* @private
* Represents the color blue;
*/

private static const BLUE:uint = 0x0000FF;

/**
* @private
* The Bitmap object that will display the bitmap data of the mask.
*/


private var _bitmap:Bitmap;

/**
* @private
* All added silhouets.
*/

private var _silhouets:Array;


/**
* The bitmap data that will be used
* in method <code>updateBitmapData()</code>.
*/

protected var data:BitmapData;






/**
* Constructor.
*
*/

public function SmartMask()
{
super();
_silhouets = [];

_bitmap = new Bitmap();
}





//------------------------------
// maskWidth

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

/**@private */
private var _maskWidth:Number = 550;


[Bindable("maskWidthChanged")]

/**
* The width of the mask, in pixels.
*/

public function get maskWidth():Number { return _maskWidth; }

/**@private */
public function set maskWidth(value:Number):void {

var oldValue:Number = _maskWidth;
_maskWidth = value;
if(oldValue != value) {

invalidateSmartMask();
dispatchEvent(new Event("maskWidthChanged"));
}
}

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

// maskHeight
//------------------------------

/**@private */
private var _maskHeight:Number = 400;


[Bindable("maskHeightChanged")]
/**
* The height of the mask, in pixels.
*/

public function get maskHeight():Number { return _maskHeight; }

/**@private */
public function set maskHeight(value:Number):void {

var oldValue:Number = _maskHeight;
_maskHeight = value;
if(oldValue != value) {

invalidateSmartMask();
dispatchEvent(new Event("maskHeightChanged"));
}
}




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

// createChildren()
//------------------------------

/**@inheritDoc */
protected override function createChildren():void {

addChild(_bitmap);
}

//------------------------------
// getSilhouetData()
//------------------------------


/**
* Returns a new BitmapData object that reflects the defined DisplayObject.
* Fully transparent pixels will be maintained.
* Other pixels will change to a color, that is not blue.
* <p>This method can be used in combination with method
* <code>addSilhouet()</code>.</p>
* @param source The DisplayObject to get the silhouet from.
* @return New BitmapData object that reflects the defined DisplayObject.
*
*/

final public function getSilhouetData(source:DisplayObject):BitmapData

{
var result:BitmapData = new BitmapData(
source.x + source.width, source.y + source.height, true, 0x00000000);

result.draw(source, source.transform.matrix, NOT_BLUE);

return result;
}

//------------------------------
// addSilhouet()
//------------------------------


/**
* Adds a silhouet to this SmartMask.
* So that we cannot see through it anymore.
* <p>The BitmapData object at
* parameter <code>silhouet</code> should not contain the color blue.
* Preferably, it'd be a transparent BitmapData object, with an opaque
* silhouet drawn in it.</p>
* @param silhouet The BitmapData object with a silhouet drawn in it.
* @throws ArgumentError Parameter silhouet is undefined.
*/

public function addSilhouet(silhouet:BitmapData):void

{
if(!silhouet) throw new ArgumentError("Parameter silhouet is undefined.");
if(getSilhouetIndex(data) != -1) return;


_silhouets.push(silhouet);
if(!data) updateSmartMask();
drawSilhouet(silhouet);

return;
}

//------------------------------
// removeSilhouet()
//------------------------------


/**
* Removes a silhouet from this SmartMask.
* So that we can see through it again.
*
* @param silhouet The BitmapData object that was
* added using <code>addSilhouet()</code>.
*
*/


public function removeSilhouet(silhouet:BitmapData):void
{
if(!silhouet) return;

var index:int = getSilhouetIndex(silhouet);
if(index == -1) return;

_silhouets.splice(index, 1);
invalidateSmartMask();
}

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

// invalidateSmartMask()
//------------------------------

/**
* Marks this smart mask invalid. So, the next frame,
* all silhouets are redrawn. Also, property <code>data</code> will be reset,
* so it's size will reflect properties
* <code>maskWidth</code> and <code>maskHeight</code> again.
*/


public function invalidateSmartMask():void {
addEventListener(Event.ENTER_FRAME, validateSmartMask);

}




//------------------------------
// validateSmartMask()
//------------------------------

/**@private */
private function validateSmartMask(event:Event):void {

removeEventListener(Event.ENTER_FRAME, validateSmartMask);
updateSmartMask();
drawAllSilhouets();

}

//------------------------------
// updateSmartMask()
//------------------------------

/**
* @private
* Resets property <code>data</code> to a new rectangle of which the size
* reflects properties <code>maskWidth</code> and <code>maskHeight</code>.
* <p>The rectangle will be colored blue. So, the silhouets should be a
* different color.</p>

*/

private function updateSmartMask():void
{
data = new BitmapData(maskWidth, maskHeight, false, BLUE);

}

//------------------------------
// drawAllSilhouets()
//------------------------------

/**
* @private
* Calls <code>drawSilhouet()</code> for every
* BitmapData object defined at <code>addSilhouet()</code>.
* @see #drawSilhouet() drawSilhouet()
*/


private function drawAllSilhouets():void
{
var i:int = _silhouets?_silhouets.length:0;

_silhouets.length = 0;
while(i-->0) {
var element:Object = _silhouets[i];

if(element is BitmapData) drawSilhouet(element as BitmapData);
}
}


//------------------------------
// drawSilhouet()
//------------------------------

/**
* @private
* Draws the <code>silhouet</code> on the BitmapData object
* at property <code>data</code>.
* <p>The BitmapData object at
* parameter <code>silhouet</code> should not contain the color blue.
* Preferably, it'd be a transparent BitmapData object, with an opaque
* silhouet drawn in it.</p>

* @param silhouet The silhouet BitmapData to draw
* on property <code>data</code>.
*
*/


private function drawSilhouet(silhouet:BitmapData):void
{
data.draw(silhouet);

invalidateBitmapData()
}

//------------------------------
// invalidateBitmapData()
//------------------------------

/**
* Marks the bitmap data of property <code>bitmap</code> invalid.
* So, this SmartMask object's display is updated the next frame,
* after calling this method.
*
* <p>This method is called internally in method <code>drawSilhouet()</code>.
* So method <code>drawSilhouet()</code> can be called multiple times in one frame,
* but the display will only be updated once.</p>

*/

protected final function invalidateBitmapData():void
{
addEventListener(Event.ENTER_FRAME, validateBitmapData);

}

//------------------------------
// validateBitmapData()
//------------------------------

/**@private */
private function validateBitmapData(event:Event):void

{
removeEventListener(Event.ENTER_FRAME, validateBitmapData);
updateBitmapData(_bitmap);

}

//------------------------------
// updateBitmapData()
//------------------------------

/**
* @private
* <p>Copies the blue pixels from the BitmapData object
* at property <code>data</code>.
* Everything bút the silhouets is colored blue.</p>

*/

private function updateBitmapData(bitmap:Bitmap):void
{

//transparent data
var output:BitmapData = new BitmapData(
maskWidth, maskHeight, true, 0x00000000);

//copy only blue pixels
output.threshold(
data, data.rect, new Point(), "==", 0xFF0000, 0xFF0000, 0xFFFFFF, true);

//update bitmap
bitmap.bitmapData = output
}

//------------------------------
// getSilhouetIndex()

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

/**@private */
private function getSilhouetIndex(silhouet:BitmapData):int

{
var i:int = _silhouets?_silhouets.length:0;

while(i-->0) {
if(_silhouets[i] == silhouet) {
return i;

}
}
return -1;
}

}
}