Binary search

Binary search is a way of searching data inside a sorted list that can drastically reduce the time of the search operations.
In this example I'm searching for an integer because it's the most reliable data type in as. When comparing strings or complex objects some expedient should be taken to be sure that the comparison it's correct. The Comparable interface of Java could be a good solution.
To give insight about how fast is this method, to run 500 searchs in a list of 1000000 items the binarySearch took 2 to 5 milliseconds doing only 16-17 comparisons.
The regular indexOf method of the Array class took 450 milliseconds to perform the same task.
The bit operations (>>>) used to take the middle number (probe) also helped a bit, using a regular division (/2) increased the time to run the task to 4-9 milliseconds.
public function binarySearch(keys:Array, target:int):int
{
var high:int = keys.length;
var low:int = -1;

while (high - low > 1)
{
var probe:int = (low + high) >>> 1;
if (keys[probe] > target)
{
high = probe;
}
else
{
low = probe;
}
}

return (low == -1 || keys[low] !== target) ? -1 : low;
}

Extending a custom component

If you are trying to extend a custom component and you get the following error

"Multiple sets of visual children have been specified for this component (base component definition and derived component definition)."

the problem is that you have created an MXML component with some children hardcoded;

Surfing the net I've found an interesting discussion here but the solution provided there hasn't convinced me at all.

After some attempts I've finally found a nice solution that is not to hardcode components inside the MXML but create components using actionscript and then add them to the displayList in the createChildren method.
override protected function childrenCreated():void{

super.childrenCreated();

if(!btn){

btn = new Button();
btn.label = "my as button";
addChild(btn);

}

}

Circular preloader

How to create a circular animation in As3, useful for preloaders
(tested on Flash Cs3/4 but it should works fine in Flex too)
var angle:Number = 0
var centerX:Number = 50
var centerY:Number = 50;
var radius:Number = 22;
var speed:Number = 0.1

var circle:Shape = new Shape();
addChild(circle)
circle.graphics.beginFill(0x00FF00);
circle.graphics.moveTo(centerX, centerY);

function onEnterFrame(e:Event) {

if (angle > 2 * Math.PI)
this.removeEventListener(Event.ENTER_FRAME, onEnterFrame)

trace("angle", angle)
circle.graphics.lineTo(centerX + Math.cos(angle) * radius,
centerY + Math.sin(angle) * radius);

angle += speed;
}
this.addEventListener(Event.ENTER_FRAME, onEnterFrame)

Duplicate a display object

Quick and dirty solution to duplicate a DisplayObject in Flash, check the duplicate flex component snippet to get a more elegant soltuion.
function duplicateDisplayObject(target:DisplayObject):DisplayObject {

// create duplicate
var targetClass:Class = Object(target).constructor;
var duplicate:DisplayObject = new targetClass();

// duplicate transformation properties
duplicate.transform = target.transform;
duplicate.filters = target.filters;
duplicate.cacheAsBitmap = target.cacheAsBitmap;
duplicate.opaqueBackground = target.opaqueBackground;

// Check the scale9
if (target.scale9Grid) {

var rectangle:Rectangle = target.scale9Grid;
duplicate.scale9Grid = rectangle;

}

return duplicate;
}

Manage bitmap output levels

Imagine to want to reach the same effect of the output levels panel you have in Photoshop through ActionScript, you can get the result by remaping the color channel values in an image that has up to four arrays of color palette data, one for each channel.

In order to do this you can simply use the paletteMap() method of the BitmapData and recalculate the values for each channel to use inside the method accordingly to 2 different points (black and white).
Download the last release of nabiro to get the class that do the job for you.
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

<mx:Script>
<![CDATA[
import com.gnstudio.nabiro.ui.images.utils.OutputLevels;
import mx.events.SliderEvent;

private var bmd:BitmapData;

override protected function childrenCreated():void{

super.childrenCreated();

var url:URLRequest = new URLRequest("central_park.jpg")

var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageCompleted);

loader.load(url);

}


private function imageCompleted(e:Event):void{

e.target.removeEventListener(e.type, arguments.callee);

bmd = Bitmap(e.currentTarget.content).bitmapData;

var output:OutputLevels = new OutputLevels(100);
image.source = new Bitmap(output.setLevels(bmd.clone(), 0, 200));

}

private function outputLevels(e:SliderEvent):void{

var output:OutputLevels = new OutputLevels(e.target.values[0] + (e.target.values[1] - e.target.values[0]) / 2);
image.source = new Bitmap(output.setLevels(bmd.clone(), e.target.values[0], e.target.values[1]));

}

]]>
</mx:Script>

<mx:Image id="image" verticalAlign="middle" complete="imageCompleted(event)" horizontalAlign="center" left="30" right="30" top="30" bottom="30"/>
<mx:HSlider bottom="5" right="30" left="30" minimum="0" maximum="255" thumbCount="2" values="[0, 255]" liveDragging="false" change="outputLevels(event)" />

load binary data via xml message

say you are dealing with a backend via xml messages, for some instance you need to load binary data. Flash player can load images, sounds, videos and other movies, but these are operations that go separated from the data exchange context. You can join xml messages and binary content using base64 classes.
The advantages are:
- concurrent messages with content
- you can build up your own distributed objects
- more opportunities to hardening your movies, e.g content protection, cryptography, progressive and conditioned loading
and the cons:
- messages are greater, almost 20/30%
- if you plan to getting touch with real data, some ByteArray skills needed
- some people prefers amf, faster and data driven
// these two code files show how to load a sample image using xml message generated from php


// as3, TryB64php.as

/**
* @author jaco
*
* created on 16/10/2009 16.56.51
*/
package {

import flash.display.*;
import flash.events.*;
import flash.text.*;
import flash.net.*;
import flash.geom.*;
import flash.utils.*;

// as3, got from http://dynamicflash.com/goodies/base64/
// if you're in flex/air, there are mx.utils.Base64* classes
import com.dynamicflash.util.Base64;


/**
*
*/
public class TryB64php extends MovieClip {

private static const PHP_URL:String = "get_xml_b64response.php";

private var ul:URLLoader;
private var ld:Loader;

/**
* the constructor
*/
function TryB64php(){

var ur:URLRequest = new URLRequest(PHP_URL);
ld = new Loader();
ul = new URLLoader();

addChild(ld);

ul.addEventListener(Event.COMPLETE, onULComplete);
ul.load(ur);
}

private function onULComplete(evt:Event):void {

var xml:XML = XML(ul.data);

var ba:ByteArray = Base64.decodeToByteArray(xml);
ld.loadBytes(ba);
}
}
}


// php, get_xml_b64response.php

<?php
/*
* Created on 16/ott/2009
*
* jaco_at_pixeldump
*/

define("XML_HEADER", "<?xml version=\"1.0\"?>");
define("NL", "\r\n");

define("RESPONSE_INFO", "info");
define("RESPONSE_VALUE_BASE64", "base64");

/**
* read resource from path
* @param file name
* @param directory
*
* @return xml instance with base64 encoded data
*/
function get_resource($resFN, $resDir = "./") {

$filePath = $resDir .$resFN;
$fRes = file_get_contents($filePath, FILE_BINARY);

return create_simpleXmlMessage(base64_encode($fRes), RESPONSE_VALUE_BASE64);
}

/**
* create an xml message
* @param message string
* @param response type
*
* @return formatted xml instance with given data
*/
function create_simpleXmlMessage($str, $type = RESPONSE_INFO) {

$xmlStr = XML_HEADER .NL;
$xmlStr .= create_xmlNode("response", $str, array("type" => $type, "timeStamp" => mktime()));

return $xmlStr;
}

/**
* create a simple xml node with some data population
* @param node name
* @param node content
* @param attributes
* @param CDATA flag
*
* @return formatted xml node with given data
*/
function create_xmlNode($nodeName, $nodeContent = "", $attrs = array(), $cDataFlag = true){

$xmlStr = "<" .$nodeName ." ";
$sfx1 = $cDataFlag ? "<![CDATA[" : "";
$sfx2 = $cDataFlag ? "]]>" : "";

if(count($attrs))
foreach($attrs as $k => $v) $xmlStr .= $k ."=\"" .$v ."\" " ;

if(strlen($nodeContent)){
$xmlStr .= ">" .$sfx1 .$nodeContent .$sfx2;
$xmlStr .= "</" .$nodeName .">";
}
else $xmlStr .= "/>";

return $xmlStr;
}

// the app

header("Content-type: text/xml");
echo get_resource("sample_avatar.png"); // sample image
?>

Edit multiple items in sorted ArrayCollection

Do following if you want to traverse through sorted ArrayCollection, update multiple items and trigger only one collection change event to optimize performance of components that use the collection.
<!--
@page { margin: 2cm }
P { margin-bottom: 0.21cm }
-->
var collection:ArrayCollection = new ArrayCollection();

collection.addItem({bar:"bar1", foo:1});
collection.addItem({bar:"bar2", foo:2});
collection.addItem({bar:"bar3", foo:3});
collection.addItem({bar:"bar4", foo:4});

var sort:Sort = new Sort();
sort.fields = [new SortField("foo")];

collection.sort = sort;
collection.refresh();

collection.addEventListener(CollectionEvent.COLLECTION_CHANGE, function(e:CollectionEvent):void {

trace(e.type);

});

collection.disableAutoUpdate();

var cursor:IViewCursor = collection.createCursor();

while (!cursor.afterLast) {

cursor.current.foo++;

cursor.view.itemUpdated(cursor.current);

cursor.moveNext();

}

collection.enableAutoUpdate();

Detect daily saving times

Thanks mainly to the efforts of a London builder named William Willett we have the controversial notion of daylight saving time (DST). This practice means that in some locations, all clocks are put one hour ahead of UTC time during the summer months.
Well, if you use local time on your site (in a real time clock for example) and your site is viewed by someone out with the US, then at certain times of year the time on your clock will be out by an hour. In the case of Europe, between the last Sunday in March and the first Sunday in April the local time on your machine will be one hour ahead of Flash local time.

This small script check the DST accordingly to US convention (first sunday of April last sunday of October) and can be adjusted for your needs in different countires.
var start:Date = new Date()

var startCounter:int = 1;
start.setMonth(3, startCounter);

for(var i:int = 0; i < 10; i++){

startCounter++
start.setMonth(3, startCounter)

if(start.getDay() == 0){

break;

}

}

var end:Date = new Date();
var endCounter:int = 31;

end.setMonth(3, endCounter);

for(var j:int = 0; j < 10; j++){

endCounter--;
end.setMonth(9, endCounter)

if(end.getDay() == 0){

break;

}

}

trace("start date", start)
trace("end date", end)

HSLIDER and VSLIDER CUSTOM SKINS (FX3)

Problem: customize the HSlider / VSlider skin and add the handcursor to the track icon
Solution: create two skin actionscript classes to customize the trackSkin and a thumbSkin styles

Main MXML File:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
backgroundColor="#999999">

<mx:Script>
<![CDATA[

// The Custom Image for the Slider Thumb
[Embed(source="assets/slider/slider_arrow.png")]
public static const SLIDER_ARROW:Class;

]]>
</mx:Script>



<!-- STANDARD SLIDER -->
<mx:HSlider width="100" height="1"
liveDragging="true"
/>

<mx:Spacer height="70" />


<!-- SLIDER WITH CUSTOM SKINS -->
<mx:HSlider width="100" height="1"
trackSkin="skins.IconSliderTrack"
thumbSkin="{SLIDER_ARROW}"
sliderThumbClass="skins.IconSliderThumb"
liveDragging="true"
/>


</mx:Application>



//==============================================================================
//skins/IconSliderTrack.as
//==============================================================================
package skins
{
import mx.core.UIComponent;

public class IconSliderTrack extends UIComponent
{

/**
* Modify the default track layout
*
*/
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void{
super.updateDisplayList(unscaledWidth, unscaledHeight);
this.graphics.moveTo(0,0);
this.graphics.lineStyle(5,0x656565);

// Draw a curve instead of the classic line
this.graphics.curveTo(unscaledWidth, 40, unscaledWidth, 0)

// Draw a Bold Line
// NOTE: if you want to use this comment the previous line
//this.graphics.lineTo(unscaledWidth,0);

}
}
}


//==============================================================================
//skins/IconSliderThumb.as
//==============================================================================
package skins {

import mx.controls.sliderClasses.SliderThumb;

public class IconSliderThumb extends SliderThumb {

public function IconSliderThumb() {
super();

/**
* You need to manually update the thumb width
* and height to the Thumg image dimensions,
* otherwise its displayed size won't be right.
* NOTE: try to comment following line to see the result
*/
this.width = 36;
this.height = 35;
this.buttonMode = true;
}
}
}





Build a STORE LOCATOR using FLEX GOOGLE MAP

I was playing with the Flex Google Map API and I think one of the coolest stuff is the Direction feature.

In few words, you can do a query like this: 'from Milano to Torino' and you'll get:
1) Distance
2) Trip duration
3) The complete travel displayed on Google Map
4) Many other usefull info (check GoogleMap website to get the API reference and other samples)

In this script I simulate a Store Locator, where user digits its city in a TextInput and at the same time he can selects a store from a List.
Each time user will change selection we'll show the trip information (Distance + trip duration) displaying visual directions on the map too.



See a live demo

But you can do more... check the Google Map Api web site for more info
and remember to sign up for a key or you won't be able to use GMAP on your web site

FLEX CODE:
Create a new Flex Project and copy all the following code inside your main mxml file.
Remember to download the GMap Flex SWC component and to copy it on your libs folder
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:maps="com.google.maps.*"
layout="absolute"
width="100%" height="100%" >


<mx:Script>
<![CDATA[
import mx.events.ListEvent;
import com.google.maps.interfaces.IPolyline;
import com.google.maps.Map;
import com.google.maps.MapEvent;
import com.google.maps.LatLng;
import com.google.maps.LatLngBounds;
import com.google.maps.overlays.Marker;
import com.google.maps.overlays.MarkerOptions;
import com.google.maps.controls.ControlPosition;
import com.google.maps.controls.MapTypeControl;
import com.google.maps.services.*;
import com.google.maps.MapAction;

import mx.controls.Alert;
import mx.collections.ArrayCollection;

private var dir:Directions;


/**
* This method is called when the default Map is loaded
*
*/
private function onMapReady(event:Event):void {
setupDirections();
controlPanel.enabled = true;
}

/**
* Define Direction class and its listeners
*
*/
private function setupDirections():void {

dir = new Directions();
dir.addEventListener(DirectionsEvent.DIRECTIONS_SUCCESS, onDirLoad);
dir.addEventListener(DirectionsEvent.DIRECTIONS_FAILURE, onDirFail);
}


/**
* Start a GMap Call to get distance between the selected store city and the user city
*
*/
private function processForm(event:ListEvent=null):void {

// Set Directions Options (see GMAP API doc for properties details)
var opts:DirectionsOptions = new DirectionsOptions({locale: "English", travelMode: "driving", avoidHighways: false})
dir.setOptions(opts);

// GMAP Query: From ... To ...
dir.load("from: " + from.text + " to: " + storeCities.selectedItem.data);

// Disable query panel
controlPanel.enabled = false;
}

/**
* Direction Wrong Query (i.e. a city wasn't found in the db)
*
*/
private function onDirFail(event:DirectionsEvent):void {
Alert.show("Status: " + event.directions.status);
controlPanel.enabled = true;
}

/**
* Direction Query SUCCESSFULLY
*
*/
private function onDirLoad(event:DirectionsEvent):void {

// Enable Query Panel
controlPanel.enabled = true;

// Get Direction object
var dir:Directions = event.directions;

// Clear previous displayed directions
map.clearOverlays();

// Display Directions on Map
var directionsPolyline:IPolyline = dir.createPolyline();
map.addOverlay(directionsPolyline);
var directionsBounds:LatLngBounds = directionsPolyline.getLatLngBounds();

// Fix map position
map.setCenter(directionsBounds.getCenter());
map.setZoom(map.getBoundsZoomLevel(directionsBounds));

// Display Markers (start and destination)
var numRoutes:Number = dir.numRoutes;
var startLatLng:LatLng = dir.getRoute(0).getStep(0).latLng;
var endLatLng:LatLng = dir.getRoute(numRoutes-1).endLatLng;
map.addOverlay(new Marker(startLatLng));
map.addOverlay(new Marker(endLatLng));

// Display trip info
infoTripTxt.htmlText = dir.summaryHtml;
}



]]>
</mx:Script>


<!--DEBUG KEY: you need to sign up for your own key-->
<maps:Map
id="map"
key="ABQIAAAA7QUChpcnvnmXxsjC7s1fCxQGj0PqsCtxKvarsoS-iqLdqZSKfxTd7Xf-2rEc_PC9o8IsJde80Wnj4g"
mapevent_mapready="onMapReady(event)"
width="100%" height="100%"/>



<mx:VBox width="395" height="200" id="controlPanel" enabled="false"
backgroundAlpha="0.8" backgroundColor="#FFFFFF">

<mx:HBox width="100%">
<mx:Label text="From (write your city):" fontWeight="bold"/>
<mx:TextInput
id="from"
text="Firenze"
width="100%" />
</mx:HBox>

<mx:HRule width="100%" />

<mx:Label fontWeight="bold"
text="To (select below the store and check the distance):"/>

<mx:HBox width="100%" height="100%" verticalAlign="middle">
<mx:List id="storeCities" width="150"
change="processForm(event)" height="121">
<mx:Object label="Milan - Outlet" data="Milan" />
<mx:Object label="Rome - Boutique" data="Rome" />
<mx:Object label="Napoli - Outlet" data="Napoli" />
<mx:Object label="Venezia - Shop" data="Venezia" />
<mx:Object label="Torino - Outlet" data="Torino" />
</mx:List>

<mx:TextArea width="220" height="60" fontSize="14" id="infoTripTxt"
backgroundAlpha="0" borderStyle="none"/>

</mx:HBox>

</mx:VBox>


</mx:Application>