In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

怪盗福笑い

MediaRSSを使って福笑い
「村(tag)の村人の顔が怪盗福笑いに奪われた」という設定で
強引にゲームっぽくしてみました。
右上の検索バーでtagを指定すると,他の村(tag)を探せます。
ちなみにスクリーンショットの村人達は"mobile"村にいました。(2010.08.29)
効果音とBGMが欲しい...
コードは,,,汚くてすいません。
既知のバグ:
最初の読み込み時に95%sで止まることがある。
顔認識するときにJPEGのエンコード処理でタイムアウトエラーが発生する場合がある。
Get Adobe Flash player
by geko 29 Aug 2010
/**
 * Copyright geko ( http://wonderfl.net/user/geko )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/ekEn
 */

// MediaRSSを使って福笑い
// 「村(tag)の村人の顔が怪盗福笑いに奪われた」という設定で
// 強引にゲームっぽくしてみました。
// 右上の検索バーでtagを指定すると,他の村(tag)を探せます。
// ちなみにスクリーンショットの村人達は"mobile"村にいました。(2010.08.29)
// 
// 効果音とBGMが欲しい...
// コードは,,,汚くてすいません。
// 
// 既知のバグ:
// 最初の読み込み時に95%sで止まることがある。
// 顔認識するときにJPEGのエンコード処理でタイムアウトエラーが発生する場合がある。

package  {
    import flash.display.*;
    import flash.events.*;
    import flash.net.*;
    import flash.system.*;
    import caurina.transitions.Tweener;
    
    [SWF(width=465, height=465, backgroundColor=0x333333)]
    public class MakeAFace extends Sprite{
        static public const ThanksMessages:Array = [["村人:ありがとう。\nイカしたオレの顔が戻ったよ。", "村人:これで明日の合コンに行けそうだ!\n助かった。本当にありがとう。"],
                                                    ["村人:おぉ,どうも。助かったよ。", "村人:それじゃ。"],
                                                    ["村人:ふぁ〜,よく寝た。\n・・・\n・・・\nあれ,勇者さんだ?何かあったのかい?", "村人:なんだか忙しいみたいだけど,勇者さんもたまには僕みたいに休んだ方がいいよ。\nそれじゃ僕は帰って寝直すよ。"],
                                                    ["村人:おぉ,私の顔が帰ってきた!\nありがとう,ありがとう!!", "村人:一時は人生をあきらめかけていたんだけど,なんとかやっていく勇気が沸いてきたよ。"],
                                                    ["???:うぁっはっはっはっはっ!!\n私が ”怪盗福笑い” だ!", "村人:なーんちゃって,うそだよーん。\n助けてくれてありがとさーん。"]];
        public var itemsPanel:ItemsPanel;
        public var setUpPanel:SetUpPanel;
        public var canvas:MakeFaceCanvas;
        public var message:MessagePanel;
        public var menuBar:MenuBar;
        public var webAPI:WebAPI = new WebAPI();
        public var target:Loader;
        public var sp:Sprite = new Sprite();
        
        public function MakeAFace(){
            //Wonderfl.capture_delay(30);
            Wonderfl.disable_capture();

            this.graphics.beginFill(0x333333);
            this.graphics.drawRect(0,0,stage.stageWidth,stage.stageHeight);
            this.graphics.endFill();            
            sp.graphics.beginFill(0,0);
            sp.graphics.drawRect(0,0,stage.stageWidth,stage.stageHeight);
            sp.graphics.endFill();
            init();
        }
        private function init():void{
            itemsPanel = new ItemsPanel(this);
            setUpPanel = new SetUpPanel(this);
            message = new MessagePanel(stage);
            itemsPanel.addEventListener(Event.COMPLETE, setUpComplete);
            itemsPanel.addEventListener(ProgressEvent.PROGRESS, progress);
            webAPI.addEventListener(Event.COMPLETE, detectFaceComplete);
            message.addEventListener(Event.COMPLETE, setUpComplete);
            itemsPanel.search("close up face");
            message.inputMessages("???:おぉ勇者よ,目覚めたか。わしは ”じいちゃん” じゃ。","じぃ:大変じゃ。お主がのんびり寝取る間に, ”怪盗福笑い” に村の者の顔が奪われてしまったのじゃ。","じぃ:勇者よ,今こそ立ち上がるときじゃ!\n ”福笑い” に立ち向かい,村の者の顔を取り戻してくるのじゃ!!\n\n\n※要は福笑いです。");
        }
        
        public function setUpComplete(event:Event):void{
            event.target.removeEventListener(Event.COMPLETE, setUpComplete);
            if((event.target == message ? itemsPanel : message).hasEventListener(Event.COMPLETE)) return;
            
            Tweener.addTween(setUpPanel, {alpha:0, time:0.8, onComplete:function comps():void{
                (setUpPanel.parent as DisplayObjectContainer).removeChild(setUpPanel);
                setUpPanel = null;
            }});
            menuBar = new MenuBar(stage.stageWidth, 25);
            stage.addChild(menuBar);

            itemsPanel.addEventListener("find", findVillage);
            itemsPanel.addEventListener("none", findVillage);
            itemsPanel.addEventListener("selectedTop", menuChange);
            itemsPanel.addEventListener("selectedVillage", menuChange);
            itemsPanel.addEventListener("selectedVillager", menuChange);
            itemsPanel.addEventListener(Event.SELECT, selected);
            menuBar.addEventListener("search", search);
            menuBar.topBt.addEventListener(MouseEvent.CLICK, itemChange);
            menuBar.villageBt.addEventListener(MouseEvent.CLICK, itemChange);
            menuBar.villagerBt.addEventListener(MouseEvent.CLICK, itemChange);
        }
        private function progress(event:ProgressEvent):void{
            if(setUpPanel) setUpPanel.value = event.bytesLoaded/event.bytesTotal;
        }

        //----
        //flickerのtag検索
        //検索開始
        private function search(event:Event):void{
            itemsPanel.search(menuBar.tag);
            message.inputMessages("じぃ: \""+menuBar.tag+"\" 村...あったかのぅ...");
            addChild(sp);
        }
        //発見
        private function findVillage(event:Event):void{
            switch(event.type){
                case "find":
                    message.inputMessages("じぃ:勇者よ,見つけたぞ!\nどうやら \""+menuBar.tag+"\" 村はあるようじゃの。");
                    if(menuBar.topBt.selected) itemsPanel.showPanel("top");
                break;
                case "none": message.inputMessages("じぃ:勇者よ,残念ながら \""+menuBar.tag+"\" 村は既に存在しないようじゃ。"); break;
            }
            removeChild(sp);
        }
        
        //-----
        //メニューとパネルの変更
        //メニューの変更
        private function menuChange(event:Event):void{
            switch(event.type){
                case "selectedTop": menuBar.change("top",[]); break;
                case "selectedVillage": menuBar.change("village", [itemsPanel.selectedVillage.name]); break;
                case "selectedVillager": menuBar.change("villager", [itemsPanel.selectedVillage.name, itemsPanel.selectedVillager.name]); break;
            }
        }
        //パネルの変更
        private function itemChange(event:MouseEvent):void{
            switch(event.currentTarget){
                case menuBar.topBt: itemsPanel.showPanel("top"); break;
                case menuBar.villageBt: itemsPanel.showPanel("village"); break;
                case menuBar.villagerBt: itemsPanel.showPanel("villager"); break;
            }
        }
        
        //-----
        //顔認識
        //村人の選択
        private function selected(event:Event):void{
            message.inputMessages("じぃ:お〜い, \""+itemsPanel.selectedVillager.name+"\" さ〜ん\nどこにおられますか〜?");
            target = new Loader();
            target.load(new URLRequest(itemsPanel.selectedVillager.url), new LoaderContext(true));
            target.contentLoaderInfo.addEventListener(Event.COMPLETE, function complete(event:Event):void{
                target.contentLoaderInfo.removeEventListener(Event.COMPLETE, complete);
                var bmd:BitmapData = new BitmapData(target.width, target.height);
                bmd.draw(target);
                webAPI.detectFace(bmd);
            });
            addChild(sp);
        }
        //顔認識完了
        private function detectFaceComplete(event:Event):void{
            var xml:XML = XML(webAPI.data);
            var faces:Array = [];
            removeChild(sp);
            //顔が見つかった
            if(xml.face.hasOwnProperty("features")){
                message.inputMessages("じぃ:おぉ,あそこに \""+itemsPanel.selectedVillager.name+"\" さんがおりますぞ。","村人:た,助けてください!\n私の顔が奪われてしまった!!");
                for each(var _xml:XML in xml.face){
                    if(!_xml.hasOwnProperty("features")) continue;
                    var face:FacialPath = new FacialPath(_xml.features);
                    faces.push(face);
                }
            }
            //顔が見つからなかった
            else{
                message.inputMessages("じぃ:おぉ,あそこに \""+itemsPanel.selectedVillager.name+"\" さんがおりますぞ。", "じぃ:どうやらこの者は顔を奪われていないようじゃ。");
                message.addEventListener(Event.COMPLETE, function complete(event:Event):void{
                    message.removeEventListener(Event.COMPLETE, complete);
                    itemsPanel.showPanel("village");
                });
            }
            
            itemsPanel.showPanel("villager");
            itemsPanel.canvas.newFace(target, faces);
            itemsPanel.canvas.addEventListener("comps", function complete(event:Event):void{
                itemsPanel.canvas.removeEventListener(Event.COMPLETE, complete);
                message.inputMessages(ThanksMessages[Math.round(Math.random()*(ThanksMessages.length-1))]);
                message.addEventListener(Event.COMPLETE, function complete(event:Event):void{
                    message.removeEventListener(Event.COMPLETE, complete);
                    itemsPanel.canvas.remove(1,0);
                });
            });
            itemsPanel.canvas.addEventListener("remove", function removed(event:Event):void{
                itemsPanel.canvas.removeEventListener(Event.REMOVED, removed);
                itemsPanel.showPanel("village");
            });
        }    
    }
}

import flash.display.*;
import flash.events.*;
import flash.filters.*;
import flash.geom.*;
import flash.net.*;
import flash.system.*;
import flash.text.*;
import flash.utils.*;
import caurina.transitions.Tweener;
import caurina.transitions.properties.ColorShortcuts;
import com.adobe.images.*;

///////////////////////////////////////////
/////////////    MainPanel    /////////////
///////////////////////////////////////////

//----------
//メインパネル
class ItemsPanel extends Sprite{
    
    public function ItemsPanel(parent:DisplayObjectContainer){
        parent.addChild(this);
        addChild(villageContainer);
        addChild(villagersContainer);
        canvas = new MakeFaceCanvas(this);
        villagersContainer.x = 465;
        canvas.x = 930;
        mediaRSS.addEventListener("find", findVillage);
        mediaRSS.addEventListener("none", noneVillage);
    }
    public function search(tag:String):void{
        this.tag = tag
        mediaRSS.search(this.tag);
    }
    private function findVillage(event:Event):void{
        var village:Village = new Village();
        village.title = tag;
        for each(var item:Object in mediaRSS.items){
            village.addVillager(item);
        }
        villages.push(village);
        villageContainer.addChild(village);
        village.x = 85*((villages.length-1)%5)+20;
        village.y = 100*(Math.floor((villages.length-1)/5))+40;
        village.addEventListener(MouseEvent.DOUBLE_CLICK, selected);
        village.addEventListener(ProgressEvent.PROGRESS, function progress(event:ProgressEvent):void{
            dispatchEvent(event);
        });
        village.addEventListener(Event.COMPLETE, function complete(event:Event):void{
            dispatchEvent(event);
        });
        selectedVillage = village;
        dispatchEvent(event);
    }
    private function noneVillage(event:Event):void{
        dispatchEvent(event);
    }
    private function selected(event:Event):void{
        switch(event.type){
            case MouseEvent.DOUBLE_CLICK:
                selectedVillage = event.currentTarget as Village;                    
                showPanel("village");
            break;
            case Event.SELECT:
                selectedVillager = selectedVillage.villager;
                dispatchEvent(event);
            break;
        }
    }
    
    public function showPanel(target:String):void{
        if(villagersContainer.numChildren) {
            villagersContainer.getChildAt(0).removeEventListener(Event.SELECT, selected);
            villagersContainer.removeChild(villagersContainer.getChildAt(0));
        }
        villagersContainer.addChild(selectedVillage.villagersContainer);
        villagersContainer.getChildAt(0).addEventListener(Event.SELECT, selected);
        Tweener.addTween(this, {x: target == "top" ? 0 : target == "village" ? -465 : -930, time:0.8});
        dispatchEvent(new Event(target == "top" ? "selectedTop" : target == "village" ? "selectedVillage" : "selectedVillager"));
    }
    
    public var mediaRSS:MediaRSS = new MediaRSS();
    public var tag:String;
    public var villages:Vector.<Village> = new Vector.<Village>();
    public var canvas:MakeFaceCanvas;
    public var selectedVillage:Village;
    public var selectedVillager:Villager;
    public var villageContainer:Sprite = new Sprite();
    public var villagersContainer:Sprite = new Sprite();
}


//----------
//福笑い用キャンバス
class MakeFaceCanvas extends Sprite{
    private var bmp:Bitmap = new Bitmap(null,"never");
    private var container:Sprite = new Sprite();

    public function MakeFaceCanvas(parent:DisplayObjectContainer) {
        parent.addChildAt(this,0);
        ColorShortcuts.init();
        init();
    }
    private function init():void{
        this.addChild(bmp);
        this.addChild(container);
        
        bmp.bitmapData = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0xFFFFFF);
    }
    
    public function newFace(source:Loader, facialPaths:Array):void{
        if(bmp.bitmapData) bmp.bitmapData.dispose();
        while(container.numChildren){
            var target:Sprite = container.getChildAt(0) as Sprite;
            container.removeChild(target);
            target = null;
        }
        
        if(!facialPaths) return;
        
        var mtrx:Matrix = new Matrix();
        scale = Math.min(stage.stageWidth/source.content.width, stage.stageHeight/source.content.height);
        dx = (stage.stageWidth-source.content.width*scale)/2;
        dy = (stage.stageHeight-source.content.height*scale)/2;
        var bmd:BitmapData = new BitmapData(source.content.width*scale, source.content.height*scale, false);
        mtrx.scale(scale, scale);
        
        bmd.draw(source, mtrx);
        bmp.bitmapData = bmd;
        bmp.x = op.x = dx;
        bmp.y = op.y = dy;
        
        trace(facialPaths.length);
        for each(var facialPath:FacialPath in facialPaths){
            var F:Sprite = new Sprite();
            var M:Sprite = new Sprite();
            var N:Sprite = new Sprite();
            var BR:Sprite = new Sprite();
            var BL:Sprite = new Sprite();
            var ER:Sprite = new Sprite();
            var EL:Sprite = new Sprite();
            container.addChild(F);
            container.addChild(M);
            container.addChild(N);
            container.addChild(BR);
            container.addChild(BL);
            container.addChild(ER);
            container.addChild(EL);
            
            drawPath(F, facialPath._facePath, 2, 0x000000, 0xFFFFFF);
            drawPath(F, facialPath._mousePath, null, null, 0xDDDDDD);
            drawPath(F, facialPath._nosePath, null, null, 0xDDDDDD);
            drawPath(F, facialPath._rightEyePath, null, null, 0xDDDDDD);
            drawPath(F, facialPath._leftEyePath, null, null, 0xDDDDDD);
            drawPath(F, facialPath._rightBrowPath, null, null, 0xDDDDDD);
            drawPath(F, facialPath._leftBrowPath, null, null, 0xDDDDDD);
            
            drawPath(M, facialPath._mousePath, 1, 0x666666, 0xDD0000, true);
            drawPath(N, facialPath._nosePath, 1, 0x666666, 0xFFFFFF, true);
            drawPath(ER, facialPath._rightEyePath, 1, 0x666666, 0x000000, true);
            drawPath(EL, facialPath._leftEyePath, 1, 0x666666, 0x000000, true);
            drawPath(BR, facialPath._rightBrowPath, 1, 0x666666, 0x996600, true);
            drawPath(BL, facialPath._leftBrowPath, 1, 0x666666, 0x996600, true);
        }
        comps = 0;
        for(var i:uint = 0; i < container.numChildren; i++){
            var parts:Sprite = container.getChildAt(i) as Sprite;
            if(i % 7 == 0) {
                comps++;
                container.addChildAt(parts,0);
                continue;
            }
            parts.addEventListener(MouseEvent.MOUSE_DOWN, drag);
            parts.addEventListener(MouseEvent.MOUSE_UP, drag);
        }
    }
    
    private function drawPath(sp:Sprite, path:GraphicsPath, thickness:Object = null, lineColor:Object = null, fillColor:Object = null, shuffle:Boolean = false):void{      
        if(shuffle){
            var minX:Number = path.data[0]*scale;
            var minY:Number = path.data[1]*scale;
            var maxX:Number = minX;
            var maxY:Number = minY;
            for(var i:uint = 2; i < path.data.length; i++){
                var data:Number = path.data[i]*scale;
                if(i%2 == 0){
                    minX = Math.min(minX, data);
                    maxX = Math.max(maxX, data);
                }
                else {
                    minY = Math.min(minY, data);
                    maxY = Math.max(maxY, data);
                }
            }
            sp.graphics.beginFill(0xFFFFFF,0);
            sp.graphics.drawRect(minX/scale-5, minY/scale-5, (maxX-minX)/scale+10, (maxY-minY)/scale+10);
            sp.graphics.endFill();
            sp.x = -minX+Math.random()*((stage.stageWidth-maxX)-10);
            sp.y = -minY+30+Math.random()*((stage.stageHeight-maxY)-10);
        }
        else{
            sp.x = dx;
            sp.y = dy;
        }
        sp.graphics.lineStyle(Number(thickness), uint(lineColor), thickness ? 1 : 0);
        if(fillColor != null) sp.graphics.beginFill(uint(fillColor));
        sp.graphics.drawPath(path.commands, path.data);
        if(fillColor != null) sp.graphics.endFill();
        sp.scaleX = sp.scaleY = scale;
    }
    
    private function drag(event:MouseEvent):void{
        var target:Sprite = event.currentTarget as Sprite;
        switch(event.type){
            case MouseEvent.MOUSE_DOWN:
                container.addChild(target);
                target.startDrag();
            break;
            case MouseEvent.MOUSE_UP:
                target.stopDrag();
                var mp:Point = new Point(target.x, target.y);
                if(Point.distance(op, mp) < 8){
                    target.removeEventListener(MouseEvent.MOUSE_DOWN, drag);
                    target.removeEventListener(MouseEvent.MOUSE_UP, drag);
                    target.x = dx;
                    target.y = dy;
                    Tweener.addTween(bmp, {_brightness:0.5, time:0.1, onComplete:function _complete():void{
                        Tweener.addTween(bmp, {_brightness:0, time:0.3});
                        if(++comps == container.numChildren) {
                            Tweener.addTween(container, {alpha:0, time:2.5, onComplete:complete,onCompleteParams:["comps"]});
                            return;
                        }
                    }});
                    dispatchEvent(new Event("set"));
                }
            break;
        }
        event.updateAfterEvent();
    }
    
    private function complete(type:String):void{
        switch(type){
            case "comps":
                while(container.numChildren){
                    var target:Sprite = container.getChildAt(0) as Sprite;
                    container.removeChild(target);
                    target = null;
                }
                container.alpha = 1;
            break;
            case "remove":
                bmp.bitmapData.dispose();
                this.alpha = 1;
            break;
        }
        dispatchEvent(new Event(type));
    }
    
    public function remove(_time:Number, _delay:Number):void{
        Tweener.addTween(this, {alpha:0, time:_time, delay:_delay,onComplete:complete,onCompleteParams:["remove"]});
    }
    
    public var scale:Number = 1;
    public var dx:Number = 0;
    public var dy:Number = 0;
    public var op:Point = new Point();
    public var comps:uint = 0;
}

//----------
//パネルアイコン
class Icon extends Sprite{
    internal var interval:uint = 0;
    internal var icon:Sprite = new Sprite();
    internal var container:Sprite = new Sprite();
    internal var _mask:Sprite = new Sprite();
    internal var txt:TextField = new TextField();
    internal var format:TextFormat = new TextFormat("Arial", 10, 0x666666, null, null, null, null, null, "center");
    internal var filterA:GlowFilter = new GlowFilter(0xFFFFFF, 0.8, 10, 10, 1, 3, true);
    internal var filterB:GlowFilter = new GlowFilter(0x333333, 0.75, 8, 8, 2, 3);
    internal var filterC:GlowFilter = new GlowFilter(0x333333, 0.5, 3, 3, 2, 3);
    private var rollOver:Boolean = false;
    
    public function Icon() {
        container.mask = _mask;
        _mask.graphics.beginFill(0x000000);
        _mask.graphics.drawRoundRect(0, 0, 75, 75, 10);
        _mask.graphics.endFill();
        txt.defaultTextFormat = format;
        txt.y = 75;
        txt.width = 75;
        txt.height = 16;
        txt.wordWrap = true;
        txt.mouseEnabled = false;
        addChild(txt);
        addChild(icon);
        icon.alpha = 0.6;
        icon.addChild(container);
        icon.addChild(_mask);
        icon.addEventListener(MouseEvent.CLICK, click);
        icon.addEventListener(MouseEvent.ROLL_OVER, function rollOver(event:MouseEvent):void{
            icon.alpha = 1;
            icon.filters = [filterA];
            txt.textColor = 0xDDDDDD;
            rollOver = true;
            title = name;
        });
        icon.addEventListener(MouseEvent.ROLL_OUT, function rollOver(event:MouseEvent):void{
            icon.alpha = 0.6;
            icon.filters = [];
            txt.textColor = 0x666666;
            rollOver = false;
            title = name;
        });
    }
    private function click(event:MouseEvent):void{
        if(getTimer()-interval < 250) dispatchEvent(new MouseEvent(MouseEvent.DOUBLE_CLICK));
        interval = getTimer();
    }
    
    public function set title(str:String):void{
        this.name = str;
        if(str.length > 8 && !rollOver) str = str.slice(0,8)+"...";
        txt.text = str;
    }
    public function get title():String{
        return txt.text;
    }

}

//----------
//村
class Village extends Icon{
    public function Village() {
        super();
    }
    
    public function addVillager(obj:Object):void{
        var villager:Villager = new Villager();
        villager.title = obj.title;
        villager.url = obj.contentURL;
        villager.load(obj.thumbnailURL);
        villagers.push(villager);
        villager.addEventListener(ProgressEvent.PROGRESS, progress);
        villager.addEventListener(Event.COMPLETE, complete);
    }
    private function progress(event:ProgressEvent):void{
        var bytesLoaded:Number = 0;
        var bytesTotal:Number = villagers.length;
        
        for each(var villager:Villager in villagers){
            if(villager.bytesLoaded) bytesLoaded += villager.bytesLoaded/villager.bytesTotal;
        }
        dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, false, false, bytesLoaded, bytesTotal));
    }
    private function complete(event:Event):void{
        event.target.removeEventListener(Event.COMPLETE, complete);
        event.target.removeEventListener(ProgressEvent.PROGRESS, progress);
        var target:Villager = event.target as Villager;
        if(++comps >= villagers.length) dispatchEvent(event);
        if(comps == 1){
            var bmd:BitmapData = new BitmapData(event.target.width, event.target.height, true, 0x00FFFFFF);
            bmd.draw(target.loader);
            container.addChild(new Bitmap(bmd));
        }
        var index:uint = villagers.indexOf(target);
        villagersContainer.addChild(target);
        target.x = 85*(index%5)+20;
        target.y = 100*(Math.floor(index/5))+40;
        target.addEventListener(MouseEvent.DOUBLE_CLICK, function doubleClick(event:MouseEvent):void{
            villager = event.currentTarget as Villager;
            villagersContainer.dispatchEvent(new Event(Event.SELECT));
        });
    }
    
    public var comps:uint = 0;
    public var villagers:Vector.<Villager> = new Vector.<Villager>();
    public var villagersContainer:Sprite = new Sprite();
    public var villager:Villager;
}

//----------
//村人
class Villager extends Icon{
    
    public function Villager() {
        super();
    }
    public function load(url:String):void{
        loader = new Loader();
        loader.load(new URLRequest(url), new LoaderContext(true));
        loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, function progress(event:ProgressEvent):void{
            bytesLoaded = event.bytesLoaded;
            bytesTotal = event.bytesTotal;
            dispatchEvent(event);
        });
        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function complete(event:Event):void{
            event.target.removeEventListener(Event.COMPLETE, complete);
            dispatchEvent(event);
        });
        container.addChild(loader);
    }
    public var loader:Loader;
    public var url:String;
    public var bytesLoaded:Number;
    public var bytesTotal:Number;
}




///////////////////////////////////////////
/////////////     MenuBar     /////////////
///////////////////////////////////////////

//----------
//MenuBar本体
class MenuBar extends Sprite{
    private var searchPanel:SearchPanel;
    
    public function MenuBar(width:Number, height:Number) {
        this.graphics.beginFill(0x000000, 0.8);
        this.graphics.drawRect(0, 0, width, height);
        this.graphics.endFill();
        
        searchPanel = new SearchPanel(100, 18);
        addChild(searchPanel);
        searchPanel.x = 330;
        searchPanel.bt.addEventListener(MouseEvent.CLICK, function click(event:MouseEvent):void{
            tag = searchPanel.text;
            if(tag) dispatchEvent(new Event("search"));
        });
        
        topBt.x = 5;
        topBt.y = villageBt.y = villagerBt.y = 2.5;
        topBt.selected = false;
        topBt.label = "村リスト";
        addChild(topBt);
    }
    
    public function change(target:String, title:Array):void{
        switch(target){
            case "top":
                if(villageBt.parent) removeChild(villageBt);
                if(villagerBt.parent) removeChild(villagerBt);
                topBt.selected = false;
                topBt.label = "村リスト";
            break;
            case "village":
                if(villagerBt.parent) removeChild(villagerBt);
                villageBt.x = topBt.x + topBt.width - 10;
                villageBt.selected = false;
                villageBt.label = "  "+title[0];
                topBt.selected = true;
                topBt.label = "村リスト";
                addChild(villageBt);
                addChild(topBt);
            break;
            case "villager":
                villageBt.x = topBt.x + topBt.width - 10;
                villageBt.selected = true;
                villageBt.label = "  "+title[0];
                villagerBt.x = villageBt.x + villageBt.width - 10;
                villagerBt.selected = false;
                villagerBt.label = "  "+title[1];
                topBt.selected = true;
                topBt.label = "村リスト";
                addChild(villagerBt);
                addChild(villageBt);
                addChild(topBt);
            break;
        }
    }
    
    public var tag:String;
    public var topBt:BreadcrumbList = new BreadcrumbList();
    public var villageBt:BreadcrumbList = new BreadcrumbList();
    public var villagerBt:BreadcrumbList = new BreadcrumbList();
}

//----------
//パン屑リスト
class BreadcrumbList extends Sprite{
    static private const DefaultColor:uint = 0xCCCCCC;
    static private const ClickColor:uint = 0x666666;
    private var container:Sprite = new Sprite();
    private var txt:TextField = new TextField();
    private var format:TextFormat = new TextFormat("Arial", 9, null, true);
    private var _selected:Boolean = false;

    public function BreadcrumbList() {
        txt.defaultTextFormat = format;
        txt.textColor = DefaultColor;
        txt.mouseEnabled = false;
        txt.x = 3;
        txt.y = 3;
        
        addChild(container);
        addChild(txt);
        container.addEventListener(MouseEvent.MOUSE_DOWN, function mouseDown(event:MouseEvent):void{
            txt.textColor = ClickColor;
            container.filters = [new GlowFilter(0x888888, 0.4, 8, 8, 1, 3, true)];
        });
        container.addEventListener(MouseEvent.MOUSE_UP, function mouseUp(event:MouseEvent):void{
            txt.textColor = DefaultColor;
            container.filters = [new GlowFilter(0xDDDDDD, 0.4, 8, 8, 1, 3, true)];
        });
        container.addEventListener(MouseEvent.ROLL_OVER, function rollOver(event:MouseEvent):void{
            txt.textColor = DefaultColor;
            container.filters = [new GlowFilter(0xDDDDDD, 0.4, 8, 8, 1, 3, true)];
        });
        container.addEventListener(MouseEvent.ROLL_OUT, function rollOut(event:MouseEvent):void{
            txt.textColor = ClickColor;
            container.filters = [];
        });
    }
    
    public function set label(str:String):void{
        if(str.length > 20) str = str.slice(0, 18) + "...";
        txt.text = str;
        txt.width = txt.textWidth+5;
        txt.height = txt.textHeight+5;
        
        container.graphics.clear();
        container.graphics.lineStyle(1,0x333333);
        container.graphics.beginFill(0x000000);
        container.graphics.lineTo(txt.width+3, 0);
        container.graphics.lineTo(txt.width+15, 10);
        container.graphics.lineTo(txt.width+3, 20);
        container.graphics.lineTo(0, 20);
        container.graphics.endFill();
    }
    public function set selected(val:Boolean):void{
        _selected = val;
        container.mouseEnabled = val;
        txt.textColor = !val ? DefaultColor : ClickColor;
    }
    public function get selected():Boolean{
        return _selected;
    }

}

//----------
//検索バー
class SearchPanel extends Sprite{
    static private const DefaultMessage:String = "他の村を探す";
    static private const DefaultColor:uint = 0x666666;
    static private const InputColor:uint = 0xAAAAAA;
    static private const EnabledColor:uint = 0x000000;
    private var txt:TextField = new TextField();
    private var format:TextFormat = new TextFormat("Arial", 9);
    private var icon:Shape = new Shape();
    
    public function SearchPanel(width:Number, height:Number) {
        txt.defaultTextFormat = format;
        txt.textColor = DefaultColor;
        txt.background = true;
        txt.backgroundColor = 0x333333;
        txt.text = DefaultMessage;
        txt.width = width;
        txt.height = txt.textHeight+5;
        txt.type = "input";
        txt.filters = [new GlowFilter(0x000000, 0.6, 6, 6, 1, 3, true)];
        txt.y = 5;
        
        bt.x = width+4;
        bt.y = 2.5;
        icon.x = 35/2;
        icon.y = 25/2;
        icon.rotation = -45;
        buttonSkin("mouseUp");
        addChild(txt);
        addChild(bt);
        bt.addChild(icon);
        txt.addEventListener(MouseEvent.CLICK, input);
        bt.addEventListener(MouseEvent.MOUSE_DOWN, function mouseDown(event:MouseEvent):void{
            bt.filters = [new GlowFilter(0x888888, 0.4, 8, 8, 1, 3, true)];
            buttonSkin(event.type);
        });
        bt.addEventListener(MouseEvent.MOUSE_UP, function mouseUp(event:MouseEvent):void{
            bt.filters = [new GlowFilter(0xDDDDDD, 0.4, 8, 8, 1, 3, true)];
            buttonSkin(event.type);
        });
        bt.addEventListener(MouseEvent.ROLL_OVER, function rollOver(event:MouseEvent):void{
            bt.filters = [new GlowFilter(0xDDDDDD, 0.4, 8, 8, 1, 3, true)];
        });
        bt.addEventListener(MouseEvent.ROLL_OUT, function rollOut(event:MouseEvent):void{
            bt.filters = [];
            buttonSkin(event.type);
        });
    }
    private function input(event:MouseEvent):void{
        txt.textColor = InputColor;
        stage.addEventListener(MouseEvent.CLICK, function click(event:MouseEvent):void{
            if(event.target == txt) return;
            txt.textColor = DefaultColor;
            stage.removeEventListener(MouseEvent.CLICK, click);
            if(!txt.text) txt.text = DefaultMessage;
        });
        txt.text = text;
    }
    
    private function buttonSkin(type:String):void{
        var iconColor:uint;
        switch(type){
            case MouseEvent.MOUSE_DOWN:
                iconColor = 0x333333;
            break;
            case MouseEvent.ROLL_OUT:
            case MouseEvent.MOUSE_UP:
                iconColor = 0x666666;
            break;
        }
        bt.graphics.clear();
        bt.graphics.beginFill(0x000000);
        bt.graphics.drawRect(0, 0, 30, 20);
        bt.graphics.endFill();
        icon.graphics.clear();
        icon.graphics.lineStyle(1.5, iconColor);
        icon.graphics.drawCircle(0, -4.5, 4);
        icon.graphics.moveTo(-0.5, -0.5);
        icon.graphics.lineTo(-0.5, 4);
    }

    public var bt:Sprite = new Sprite();
    public function get text():String{
        return txt.text == DefaultMessage ? "" : txt.text;
    }
}

///////////////////////////////////////////
///////////     その他Panel     ///////////
///////////////////////////////////////////

//----------
//セットアップパネル
class SetUpPanel extends Sprite{
    static private const LABEL:String = "Make a Face";
    private var container:Sprite = new Sprite();
    private var loadedContainer:Sprite = new Sprite();
    private var maskSprite:Sprite = new Sprite();
    private var normalLabel:TextField = new TextField();
    private var loadedLabel:TextField = new TextField();
    private var txt:TextField = new TextField();
    private var format:TextFormat = new TextFormat("Arial", 30, null, true, null, null, null, null, "center");

    public function SetUpPanel(parent:DisplayObjectContainer) {
        parent.addChild(this);
        init();
    }
    private function init():void{
        this.graphics.beginFill(0x000000);
        this.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
        this.graphics.endFill();
        
        normalLabel.defaultTextFormat = loadedLabel.defaultTextFormat = format;
        normalLabel.textColor = 0x545454;
        loadedLabel.textColor = 0xDDDDDD;
        normalLabel.text = loadedLabel.text = LABEL;
        normalLabel.width = loadedLabel.width = normalLabel.textWidth+5;
        normalLabel.height = loadedLabel.height = normalLabel.textHeight;
        normalLabel.mouseEnabled = loadedLabel.mouseEnabled = false;
        
        format.size = 14;
        txt.defaultTextFormat = format;
        txt.textColor = 0xAAAAAA;
        txt.text = "0%";
        txt.x = loadedLabel.x;
        txt.y = loadedLabel.height+3;
        txt.width = loadedLabel.width;
        txt.height = txt.textHeight+3;
        txt.mouseEnabled = false;
        
        loadedContainer.mask = maskSprite;
        maskSprite.y = loadedLabel.height-3;
        
        addChild(container);
        container.addChild(normalLabel);
        container.addChild(txt);
        container.addChild(loadedContainer);
        loadedContainer.addChild(loadedLabel);
        loadedContainer.addChild(maskSprite);
        
        container.x = (stage.stageWidth-container.width)/2;
        container.y = (stage.stageHeight-container.height)/2;
        
    }
    
    public function set value(val:Number):void{
        val = Math.min(val, 1);
        maskSprite.graphics.clear();
        maskSprite.graphics.beginFill(0xFFFFFF,0.4);
        maskSprite.graphics.drawRect(0, -val*(maskSprite.y-7), loadedLabel.width, val*(maskSprite.y-7));
        maskSprite.graphics.endFill();
        
        txt.text = String(Math.round(val*100)+"%");
    }
    public function get value():Number{
        return maskSprite.height/maskSprite.y;
    }
}

//----------
//メッセージパネル
class MessagePanel extends Sprite{
    private var txt:TextField = new TextField();
    private var format:TextFormat = new TextFormat("Arial", 20, 0xDDDDDD, true);
    private var flipIcon:Shape = new Shape();
    private var message:Array;
    private var timer:Timer = new Timer(100);
    private var _parent:DisplayObjectContainer;

    public function MessagePanel(parent:DisplayObjectContainer) {
        _parent = parent;
        init();
    }
    private function init():void{
        this.graphics.beginFill(0x000000, 0);
        this.graphics.drawRect(0, 0, 465, 465);
        this.graphics.endFill();
        this.graphics.lineStyle(5, 0xDDDDDD);
        this.graphics.beginFill(0x000000);
        this.graphics.drawRoundRect(0, 315, 465, 150, 10);
        this.graphics.endFill();
        
        flipIcon.graphics.beginFill(0xDDDDDD);
        flipIcon.graphics.lineTo(10, -15);
        flipIcon.graphics.lineTo(-10, -15);
        flipIcon.graphics.endFill();
        flipIcon.x = 440;
        flipIcon.y = 460;
        
        txt.defaultTextFormat = format;
        txt.x = 20;
        txt.y = 335;
        txt.width = 425;
        txt.height = 120;
        txt.mouseEnabled = false;
        txt.wordWrap = true;
        addChild(txt);
        
        this.addEventListener(MouseEvent.CLICK, click);
        timer.addEventListener(TimerEvent.TIMER, textAnimation);
    }
    
    public function inputMessages(...messages):void{
        txt.text = "";
        this.messages = this.message = [];
        _parent.addChild(this);
        if(messages[0] is Array){
            this.messages = messages[0].concat();
        }
        else {
            this.messages = messages.concat();
        }
        message = this.messages.shift().toString().split("");
        timer.start();
    }
    
    private function textAnimation(event:TimerEvent):void{
        if(message.length){
            txt.appendText(message.shift());
        }else{
            timer.stop();
            flipAnimation();
        }
    }
    
    private function click(event:MouseEvent):void{
        if(message.length){
            while(message.length){
                txt.appendText(message.shift());
            }
        }else if(messages.length){
            txt.text = "";
            message = messages.shift().toString().split("");
            timer.start();
        }else{
            dispatchEvent(new Event(Event.COMPLETE));
            timer.stop();
            _parent.removeChild(this);
        }
    }
    
    private function flipAnimation():void{
        if(timer.running) {
            if(flipIcon.parent) removeChild(flipIcon);
            return;
        }
        if(this.parent){
            addChild(flipIcon);
            Tweener.addTween(flipIcon, {y:flipIcon.y == 462 ? 460 : 462, time:0.2, delay:0.1, onComplete:flipAnimation});
        }
    }
    
    public var messages:Array;

}

///////////////////////////////////////////
/////////////     Web関連     /////////////
///////////////////////////////////////////

//----------
//MediaRSS    
class MediaRSS extends EventDispatcher{
    private var feed:String = "http://api.flickr.com/services/feeds/photos_public.gne?format=rss_200&tags=";
    private var media:Namespace = new Namespace("http://search.yahoo.com/mrss/");
    
    public function MediaRSS() {}
    private function mediaRSSReader():void{
        var urlLoader:URLLoader = new URLLoader();
        urlLoader.addEventListener(Event.COMPLETE, function load(event:Event):void {
            urlLoader.removeEventListener(Event.COMPLETE, load);
            setContentsInfo(XML(urlLoader.data));
        });
        urlLoader.load(new URLRequest(feed+tag));
    }
    private function setContentsInfo(rss:XML):void{
        //タグが見つからなかった場合
        if(!rss..item[0]) {
            dispatchEvent(new Event("none"));
            return;
        }
        
        for each(var xml:XML in rss..item){
            var item:Object = new Object();
            item.contentURL = xml.media::content.@url;
            item.title = xml.media::title;
            item.tags = xml.media::category.split(" ");
            item.thumbnailURL = xml.media::thumbnail.@url;
            items.push(item);
        }
        dispatchEvent(new Event("find"));
    }
    //検索
    public function search(tag:String = ""):void{
        if(tag) this.tag = tag;
        items = new Vector.<Object>();
        mediaRSSReader();
    }

    //格納変数
    public var items:Vector.<Object>;
    //public var contents:Array;
    //検索タグ
    public var tag:String = "";
    //public var comps:uint = 0;
}

//----------
//WebAPI
class WebAPI extends EventDispatcher{
    public static var URL:String = "http://detectface.com/api/detect";
    public function WebAPI(){}
    
    public function detectFace(source:BitmapData):void{
        //画像の準備
        var jpegEncoder:JPGEncoder = new JPGEncoder(40);
        var data:ByteArray = jpegEncoder.encode(source);
        
        var request:URLRequest = new URLRequest(URL);
        request.data = data;
        request.method = URLRequestMethod.POST;
        request.contentType = "image/jpeg";
        
        loaded = true;
        var loader:URLLoader = new URLLoader(request);
        loader.addEventListener(Event.COMPLETE, complete);
        loader.addEventListener(IOErrorEvent.IO_ERROR, ioError);
    }
    private function ioError(event:IOErrorEvent):void{
        loaded = false;
        dispatchEvent(event);
    }
    private function complete(event:Event):void{
        data = event.target.data;
        loaded = false;
        dispatchEvent(event);
    }
    
    public var data:*;
    public var loaded:Boolean = false;
}

//----------
//顔認識>>GraphicsPath変換
class FacialPath {
    public function FacialPath(faceInfo:XMLList = null) {
        if(faceInfo) getFacialPath(faceInfo);
    }
    
    public function getFacialPath(faceInfo:XMLList):void{
        _facePath = getPath(faceInfo, 10, "F");
        _mousePath = getPath(faceInfo, 9, "M");
        _nosePath = getPath(faceInfo, 4, "N", true);
        _rightEyePath = getPath(faceInfo, 6, "ER");
        _leftEyePath = getPath(faceInfo, 6, "EL");
        _rightBrowPath = getPath(faceInfo, 6, "BR");
        _leftBrowPath = getPath(faceInfo, 6, "BL");
    }

    //パスの計算
    static private function getPath(faceInfo:XMLList, count:uint, id:String, curve:Boolean = false):GraphicsPath{
        var path:GraphicsPath = new GraphicsPath();
        var positive:Boolean;

        for(var i:uint = 1; i <= count; i++){
            var point:XMLList = faceInfo.point.(@id.toString() === String(id+i));
            if(i == 1){
                path.moveTo(point.@x,point.@y);
            }
            else{
                if(curve){
                    positive = (path.data[path.data.length-2]-point.@x)*(path.data[path.data.length-1]-point.@y) > 0 ? true : false;
                    path.curveTo(positive ? path.data[path.data.length-2] : point.@x,
                                 positive ? point.@y : path.data[path.data.length-1],
                                 point.@x, point.@y);
                }
                else{
                    path.lineTo(point.@x, point.@y);
                }
            }
        }
        
        if(curve){
            positive = (path.data[path.data.length-2]-path.data[0])*(path.data[path.data.length-1]-path.data[1]) > 0 ? true : false;
            path.curveTo(positive ? path.data[path.data.length-2] : path.data[0], 
                         positive ? path.data[1] : path.data[path.data.length-1], 
                         path.data[0], path.data[1]);
        }
        else {
            path.lineTo(path.data[0], path.data[1]);
        }
        return path;
    }
    
    //プロパティ
    public var _facePath:GraphicsPath;
    public var _mousePath:GraphicsPath;
    public var _nosePath:GraphicsPath;
    public var _rightEyePath:GraphicsPath;
    public var _leftEyePath:GraphicsPath;
    public var _rightBrowPath:GraphicsPath;
    public var _leftBrowPath:GraphicsPath;
}