forked from: Happy Birthday Koko ;-)
    koko さんおたんじょうびおめでとーございまーす :-)
*  happy birthday な画像を使って happy birthday を作るよ。
*
*  @see http://www.flickr.com/groups/happybirthday/
    
    
    
    
    
   
  /**
 * Copyright mickymac ( http://wonderfl.net/user/mickymac )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/9WWa
 */
// forked from soundkitchen's Happy Birthday Koko ;-)
/**
 *  koko さんおたんじょうびおめでとーございまーす :-)
 *  happy birthday な画像を使って happy birthday を作るよ。
 *
 *  @see http://www.flickr.com/groups/happybirthday/
 */
package
{
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageQuality;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import com.flashdynamix.utils.SWFProfiler;
    import org.libspark.thread.EnterFrameThreadExecutor;
    import org.libspark.thread.Thread;
    [SWF(width=465, height=465, frameRate=30, backgroundColor=0x000000)]
    /**
     *  document class.
     */
    public class HappyBirthdayKoko extends Sprite
    {
        /**
         *  constructor.
         */
        public function HappyBirthdayKoko()
        {
            Wonderfl.disable_capture();
            addEventListener(Event.ADDED_TO_STAGE, initialize);
        }
        /**
         *  initialize.
         */
        private function initialize(evt:Event):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, initialize);
            if (!Thread.isReady)
            {
                //  setup stage.
                stage.align = StageAlign.TOP_LEFT;
                stage.quality = StageQuality.HIGH;
                stage.scaleMode = StageScaleMode.NO_SCALE;
                //
                Thread.initialize(new EnterFrameThreadExecutor());
                //  setup debugger.
                SWFProfiler.init(this);
            }
            new MainThread(this).start();
        }
    }
}
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BlendMode;
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Graphics;
import flash.display.Loader;
import flash.display.PixelSnapping;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Matrix;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLVariables;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.system.LoaderContext;
import com.adobe.serialization.json.JSON;
import org.libspark.betweenas3.BetweenAS3;
import org.libspark.betweenas3.easing.*;
import org.libspark.betweenas3.tweens.ITween;
import org.libspark.thread.Monitor;
import org.libspark.thread.Thread;
import org.libspark.thread.threads.display.LoaderThread;
import org.libspark.thread.threads.net.URLLoaderThread;
import org.libspark.thread.threads.tweener.TweenerThread;
import org.libspark.thread.utils.ParallelExecutor;
/**
 *  main thread.
 */
internal class MainThread extends Thread
{
    private var _layer:DisplayObjectContainer;
    private var _jsonLoader:URLLoader;
    /**
     *  constructor.
     */
    public function MainThread(layer:DisplayObjectContainer)
    {
        _layer = layer;
    }
    /**
     *  show waiting message.
     */
    override protected function run():void
    {
        var th:Thread;
        th = new FixBackgroundThread(_layer);
        th.start();
        th = new WaitAnimationThread(_layer);
        th.start();
        th.join();
        next(loadData);
        interrupted(empty);
    }
    /**
     *  laod data from YQL.
     */
    private function loadData():void
    {
        var req:URLRequest,
            data:URLVariables,
            th:Thread;
        _jsonLoader = new URLLoader();
        data = new URLVariables();
        data['format'] = "json";
        data['diagnostics'] = "false";
        data['q'] = "SELECT * FROM flickr.photos.search(50) WHERE group_id = '62402008@N00'";
        req = new URLRequest();
        req.url = "http://query.yahooapis.com/v1/public/yql";
        req.data = data;
        th = new URLLoaderThread(req, _jsonLoader);
        th.start();
        th.join();
        next(animate);
        interrupted(empty);
    }
    /**
     *
     */
    private function animate():void
    {
        var json:Object,
            row:Object,
            urls:Vector.<String>,
            pool:ImagePool,
            tasks:ParallelExecutor;
        json = JSON.decode(_jsonLoader.data);
        urls = new Vector.<String>();
        for each (row in json.query.results.photo)
        {
            urls.push("http://farm" + row.farm + ".static.flickr.com/" +
                      row.server + "/" + row.id + "_" + row.secret + "_s.jpg");
        }
        Wonderfl.capture_delay(5);
        
        pool = new ImagePool();
        tasks = new ParallelExecutor();
        tasks.addThread(new LoadImageThread(urls, pool));
        tasks.addThread(new LoadImageThread(urls, pool));
        tasks.addThread(new LoadImageThread(urls, pool));
        tasks.addThread(new LoadImageThread(urls, pool));
        tasks.addThread(new LoadImageThread(urls, pool));
        tasks.addThread(new LoadImageThread(urls, pool));
        tasks.addThread(new DisplayImageThread(_layer, pool));
        tasks.start();
    }
    /**
     *  empty task.
     */
    private function empty(...args):void
    {
        //  nothing to do.
    }
    /**
     *  finalize the object.
     */
    override protected function finalize():void
    {
        _layer = null;
    }
}
/**
 *
 */
internal class WaitAnimationThread extends Thread
{
    private var _layer:DisplayObjectContainer;
    private var _message:DisplayObject;
    /**
     *
     */
    public function WaitAnimationThread(layer:DisplayObjectContainer)
    {
        _layer = layer;
    }
    /**
     *
     */
    override protected function run():void
    {
        var txt:TextField,
            data:BitmapData,
            stage:Stage;
        stage = _layer.stage;
        txt = new TextField();
        txt.autoSize = TextFieldAutoSize.LEFT;
        txt.defaultTextFormat = new TextFormat("Lucida Grande", 36);
        txt.text = "click to start";
        data = new BitmapData(txt.width, txt.height, true, 0);
        data.draw(txt);
        _message = new Bitmap(data, PixelSnapping.AUTO, true);
        _message.blendMode = BlendMode.INVERT;
        _message.x = (stage.stageWidth - _message.width) >> 1;
        _message.y = (stage.stageHeight - _message.height) >> 1;
        _layer.addChild(_message);
        event(stage, MouseEvent.CLICK, clickHandler);
    }
    private function clickHandler(evt:MouseEvent):void
    {
        var th:Thread;
        th = new HideMessageThread(_message);
        th.start();
    }
    /**
     *
     */
    override protected function finalize():void
    {
        _layer = null;
        _message = null;
    }
}
/**
 *
 */
internal class HideMessageThread extends Thread
{
    private var _message:DisplayObject;
    /**
     *  constructor.
     */
    public function HideMessageThread(message:DisplayObject)
    {
        _message = message;
    }
    /**
     *  hide message.
     */
    override protected function run():void
    {
        var th:Thread;
        th = new TweenerThread(_message, {
            alpha: 0,
            time: 1,
            transition: "easeOutCubic"
        });
        th.start();
        th.join();
        next(complete);
        interrupted(empty);
    }
    /**
     *  remove message from parent.
     */
    private function complete():void
    {
        var parent:DisplayObjectContainer;
        parent = _message.parent;
        if (parent)
            parent.removeChild(_message);
    }
    /**
     *  empty task.
     */
    private function empty(...args):void
    {
        //  do nothing.
    }
    /**
     *  finalize the object.
     */
    override protected function finalize():void
    {
        _message = null;
    }
}
/**
 *  load image from flickr.
 */
internal class LoadImageThread extends Thread
{
    private var _data:Vector.<String>;
    private var _pool:ImagePool;
    private var _loader:Loader;
    /**
     *  constructor.
     */
    public function LoadImageThread(data:Vector.<String>, pool:ImagePool)
    {
        _data = data;
        _pool = pool;
    }
    /**
     *  load image.
     */
    override protected function run():void
    {
        var req:URLRequest,
            ctx:LoaderContext,
            th:Thread;
        if (!_data.length) return;
        _loader = new Loader();
        req = new URLRequest(_data.shift());
        ctx = new LoaderContext(true);
        th = new LoaderThread(req, ctx, _loader);
        th.start();
        th.join();
        next(complete);
        error(Error, failure);
    }
    /**
     *  stack data to queue and rewind.
     */
    private function complete():void
    {
        var data:BitmapData;
        data = new BitmapData(_loader.width, _loader.height, false, 0);
        data.draw(_loader);
        _pool.offer(data);
        _loader.unload();
        _loader = null;
        next(run);
    }
    /**
     *  error fallback.
     */
    private function failure(e:Error, t:Thread):void
    {
        _loader.unload();
        _loader = null;
        next(run);
    }
    /**
     *  finalize the object.
     */
    override protected function finalize():void
    {
        _data = null;
        _pool = null;
    }
}
/**
 *  show image.
 */
internal class DisplayImageThread extends Thread
{
    private var _layer:DisplayObjectContainer;
    private var _container:Sprite;
    private var _pool:ImagePool;
    private var _map:Vector.<uint>;
    private var _width:uint;
    private var _height:uint;
    private var _index:uint;
    /**
     *  constructor.
     */
    public function DisplayImageThread(layer:DisplayObjectContainer, pool:ImagePool)
    {
        _layer = layer;
        _pool = pool;
        _index = 0;
    }
    /**
     *  create map.
     */
    override protected function run():void
    {
        var i:uint, j:uint,
            l:uint, m:uint,
            txt:TextField,
            map:BitmapData,
            stage:Stage;
        stage = _layer.stage;
        txt = new TextField();
        txt.autoSize = TextFieldAutoSize.LEFT;
        txt.defaultTextFormat = new TextFormat("Arial", 18, 0x000000);//, true);
        txt.text = "Happy\nBirthday\nKoko";
        _width = txt.width >> 0;
        _height = txt.height >> 0;
        map = new BitmapData(_width, _height, true, 0);
        map.draw(txt);
        _map = new Vector.<uint>();
        for (i=0; i<_height; i++)
        {
            for (j=0; j<_width; j++)
            {
                if (map.getPixel32(j, i))
                {
                    _map.push(i*_width+j);
                }
            }
        }
        map.dispose();
        _container = new Sprite();
        _container.transform.matrix = new Matrix(.08, 0, 0, .08,
                                                 stage.stageWidth>>1,
                                                 stage.stageHeight>>1);
        _layer.addChild(_container);
        next(update);
    }
    private function update():void
    {
        var i:uint,
            data:BitmapData,
            bitmap:Bitmap,
            th:Thread,
            tw:ITween,
            angle:Number,
            strength:Number,
            tx:Number, ty:Number;
        if (_pool.check())
        {
            bitmap = new Bitmap(_pool.pickup());
            i = Math.random() * _map.length >> 0;
            i = _map.splice(i, 1).pop();
            tx = int(i % _width) * bitmap.width - _width * bitmap.width / 2;
            ty = int(i / _width) * bitmap.height - _height * bitmap.height / 2;
            angle = Math.random() * Math.PI * 2;
            strength = Math.random() * 200 / _container.scaleX;
            bitmap.alpha = 0;
            bitmap.x = tx + Math.cos(angle) * strength;
            bitmap.y = ty + Math.sin(angle) * strength;
            bitmap.scaleX = bitmap.scaleY = 2 / _container.scaleX;
            tw = BetweenAS3.serial(
                BetweenAS3.addChild(bitmap, _container),
                BetweenAS3.to(bitmap, {
                    x: tx,
                    y: ty,
                    scaleX: 1,
                    scaleY: 1,
                    alpha: 1
                }, 1.5, Expo.easeIn)
            );
            tw.play();
        }
        next(_map.length ? update : complete);
    }
    private function complete():void
    {
        var tw:ITween;
        tw = BetweenAS3.tween(_container, {
            transform: {
                colorTransform: {
                    redMultiplier: 5,
                    greenMultiplier: 5,
                    blueMultiplier: 5
                }
            },
            _glowFilter: {
                color: 0xFFFFFF,
                alpha: .5,
                blurX: 32,
                blurY: 32
            }
        }, {
            _glowFilter: {
                color: 0xFFFFFF,
                alpha: 0,
                blurX: 0,
                blurY: 0
            }
        }, 1.6, Cubic.easeIn);
        tw = BetweenAS3.serial(
            BetweenAS3.delay(tw, 1.6),
            BetweenAS3.reverse(tw)
        );
        tw.play();
    }
    /**
     *
     */
    override protected function finalize():void
    {
        _layer = null;
        _container = null;
        _pool = null;
    }
}
/**
 *  fix background layer.
 */
internal class FixBackgroundThread extends Thread
{
    private var _layer:DisplayObjectContainer;
    private var _background:Shape;
    /**
     *  constructor.
     */
    public function FixBackgroundThread(layer:DisplayObjectContainer)
    {
        _layer = layer;
    }
    /**
     *
     */
    override protected function run():void
    {
        _background = new Shape();
        _layer.addChild(_background);
        update();
    }
    private function update():void
    {
        var stage:Stage,
            gr:Graphics;
        stage = _layer.stage;
        if (!stage) return;
        gr = _background.graphics;
        gr.clear();
        gr.beginFill(0);
        gr.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
        gr.endFill();
        event(stage, Event.RESIZE, resizeHandler);
        interrupted(empty);
    }
    private function resizeHandler(evt:Event):void
    {
        update();
    }
    private function empty(...args):void
    {
        //  nothing to do.
    }
    /**
     *  finalize the object.
     */
    override protected function finalize():void
    {
        _layer.removeChild(_background);
        _layer = null;
        _background = null;
    }
}
/**
 *  image pool
 */
internal class ImagePool
{
    private var _pool:Vector.<BitmapData>;
    private var _monitor:Monitor;
    /**
     *  check pool is empty.
     */
    public function get isEmpty():Boolean
    {
        return _pool.length == 0;
    }
    /**
     *  constructor.
     */
    public function ImagePool()
    {
        _pool = new Vector.<BitmapData>();
        _monitor = new Monitor();
    }
    /**
     *  check data available.
     */
    public function check():Boolean
    {
        var f:Boolean = true;
        if (isEmpty)
        {
            f = false;
            _monitor.wait();
        }
        return f;
    }
    /**
     *  pickup image.
     */
    public function pickup():BitmapData
    {
        return _pool[int(Math.random() * _pool.length)];
    }
    /**
     *  stack new data.
     */
    public function offer(data:BitmapData):void
    {
        _pool.push(data);
        _monitor.notifyAll();
    }
}