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

forked from: Alternativa3D Picture Book

Alternativa3D を簡単に扱うためのベーシックテンプレート
@author Yasu (clockmaker)

Alternativa3D 
読み込んだ画像で、絵本を作る
画像の読み込みに少し時間がかかります.
キーボードの十字キーとPageUp PageDownで、カメラを動かせます。
@narutohyper
/**
 * Copyright m89 ( http://wonderfl.net/user/m89 )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/BpNk
 */

// forked from narutohyper's Alternativa3D Picture Book
// forked from clockmaker's [Alternativa3D] Basic Template
package {
    import alternativ5.engine3d.materials.FillMaterial;
    import alternativ5.engine3d.primitives.Box;
    import alternativ5.engine3d.primitives.Plane;
    import alternativ5.engine3d.events.MouseEvent3D
    import alternativ5.types.Point3D;
    import flash.display.*;
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.events.ProgressEvent;    
    import flash.net.URLRequest;
    import flash.system.LoaderContext;
    import flash.ui.Mouse;
    import flash.system.Security; 
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFormat;          
    
    [SWF(width = 465, height = 465, frameRate = 60)]
    /**
     * Alternativa3D を簡単に扱うためのベーシックテンプレート
     * @author Yasu (clockmaker)
     */
    /**
     * Alternativa3D 
     * 読み込んだ画像で、絵本を作る
     * 画像の読み込みに少し時間がかかります.
     * キーボードの十字キーとPageUp PageDownで、カメラを動かせます。
     * @narutohyper
     */
     
    public class SimpleDemo extends Sprite {

        //後々外部xmlからの読み込みに対応させるられるよう、XMLで、画像のURLを設定
        private var dataXml:XML =
            <menu>
                    <imgurl>http://marubayashi.net/archive/sample/images/top.jpg</imgurl>
                    <imgurl>http://marubayashi.net/archive/sample/images/sample01.jpg</imgurl>
                    <imgurl>http://marubayashi.net/archive/sample/images/sample02.jpg</imgurl>
                    <imgurl>http://marubayashi.net/archive/sample/images/sample03.jpg</imgurl>
                    <imgurl>http://marubayashi.net/archive/sample/images/sample04.jpg</imgurl>
                    <imgurl>http://marubayashi.net/archive/sample/images/sample05.jpg</imgurl>
            </menu>;


        private var plate:Plane;

        private var dataCounter:uint=0;
        private var dataArray:Array;
        private var imgArray:Array;

        private var nowPage:uint=0;
        private var nextPage:uint=0;
        private var interactiveFlag:Boolean=true;
        private var buttonFlag:Boolean=true;
        private var pagePitch:Number=0.5;
        private var cameraZoom:Number;
        private var cameraAngle:Number;
        private var dbg:TextField;
        
        public function SimpleDemo():void {

            dbg=new TextField()
            dbg.autoSize=TextFieldAutoSize.LEFT
            dbg.selectable=false;
            dbg.mouseEnabled=false;
            var format:TextFormat=new TextFormat();
            format.color=0x666666
            format.size=12;
            format.font='_ゴシック';
            dbg.defaultTextFormat=format
            this.addChild(dbg)

            dataArray = new Array();
            imgArray = new Array();

            //取り込んだXMLデータの中の画像URL情報を配列に収納
            for each (var item:String in dataXml.imgurl) {
                dataArray.push(item)
            }
            Security.loadPolicyFile('http://marubayashi.net/crossdomain.xml'); 
            
            //画像の読み込み開始
            imgLoader(0)

        }


        //画像読み込み
        private function imgLoader(no:uint):void {
            var bytesLoaded:Number;
            var bytesTotal:Number;
            dbg.appendText(dataArray[no]+' now loading '+"\n");
            var loader:Loader = new Loader();
            loader.load(new URLRequest(dataArray[no]));
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE,loaded);
            loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS,progressHandler);

            loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, error); 

            //読み込み監視
            function progressHandler(event:ProgressEvent):void {
                bytesLoaded = event.bytesLoaded
                bytesTotal  = event.bytesTotal
                dbg.text=dataArray[no]+' now loading '+uint(bytesLoaded / bytesTotal)+"\n";
            }

            function loaded(e:Event):void {
                dbg.appendText(dataArray[no]+' END'+"\n");
                imgArray.push(loader);
                dbg.appendText(dataArray[no]+' OK'+"\n");
                nextProc()
            }

            function error(e:IOErrorEvent):void {
                dbg.appendText(dataArray[no]+' BAT'+"\n");
                nextProc()
            }

            function nextProc():void {
                dataCounter++
                if (dataArray.length>dataCounter) {
                    imgLoader(dataCounter)
                } else {
                    init();
                }
            }
        }


        private function init():void {
            this.removeChild(dbg)
            // テンプレートを作成します
            var template:BasicTemplate = new BasicTemplate();
            addChild(template);

            template.camera.x = 0
            template.camera.y = -940
            template.camera.z = 500


            var myController:rollingCameraController = new rollingCameraController(template,stage,template.camera,200,-90)

            // 背景用プリミティブを作成します
            plate=new Plane(2000,1000,8,8,true,true)
            plate.cloneMaterialToAllSurfaces(new FillMaterial(0x666666,1,BlendMode.NORMAL,-1,0x666666));
            plate.coords=new Point3D(0,0,-100);
            template.scene.root.addChild(plate);

            //Plateでは、rolloverしても、マウスカーソルはオフのまま
            plate.addEventListener(MouseEvent3D.MOUSE_OVER, cursorOff);
            plate.addEventListener(MouseEvent3D.MOUSE_OUT, cursorOff);


            // プリミティブを作成します
            var planeArray:Array=[]
            for (var i:uint=0;i<=imgArray.length;i++) {
                if (i==0) {
                    planeArray[i] = new page3D(i,imgArray[0],'front');
                } else if (i==imgArray.length) {
                    planeArray[i] = new page3D(i,imgArray[0],'back');
                } else {
                    planeArray[i] = new page3D(i,imgArray[i]);
                }
                template.scene.root.addChild(planeArray[i]);

                planeArray[i].z=(imgArray.length-i)*pagePitch;
                planeArray[i].addEventListener(page3D.MOUSE_OVER, cursorOn);
                planeArray[i].addEventListener(page3D.MOUSE_OUT, cursorOff);
                planeArray[i].addEventListener(page3D.LEFT_CLICK, onNextPage);
                planeArray[i].addEventListener(page3D.RIGHT_CLICK, onBackPage);

            }


            function cursorOn(e:*):void {
                if (interactiveFlag) {
                    template.view.buttonMode = true;
                }
                buttonFlag=true;
            }

            function cursorOff(e:*):void {
                template.view.buttonMode = false;
                buttonFlag=false;
            }


            function onNextPage(e:*):void {
                var maxPage:uint=imgArray.length
                if (interactiveFlag) {
                    nextPage++
                    if (nextPage>maxPage) {
                        nextPage=maxPage
                    }
                    if(nowPage!=nextPage) {
                        interactiveFlag=false;
                        template.view.buttonMode = false;
                        if (planeArray[nextPage-1]) {
                            planeArray[nextPage-1].closeLeft()
                        }
                        if (planeArray[nextPage]) {
                            planeArray[nextPage].openRight()
                            planeArray[nextPage].addEventListener(page3D.OPEN_END, clickEnd);
                        }
                        for (var i:uint=0;i<=maxPage;i++) {
                            planeArray[i].setIndex(maxPage,pagePitch,Math.abs(i-nextPage),i-nextPage)
                        }
                        nowPage=nextPage
                    }
                }
            }

            function onBackPage(e:*):void {
                var maxPage:uint=imgArray.length
                if (interactiveFlag) {
                    nextPage--
                    if (nextPage<0) {
                        nextPage=0
                    }
                    if(nowPage!=nextPage) {
                        interactiveFlag=false;
                        template.view.buttonMode = false;
                        if (planeArray[nextPage+1]) {
                            planeArray[nextPage+1].closeRight()
                        }
                        if (planeArray[nextPage]) {
                            planeArray[nextPage].openLeft()
                            planeArray[nextPage].addEventListener(page3D.OPEN_END, clickEnd);
                        }

                        for (var i:uint=0;i<=maxPage;i++) {
                            planeArray[i].setIndex(maxPage,pagePitch,Math.abs(i-nextPage),i-nextPage)
                        }
                        nowPage=nextPage
                    }
                }
            }

            function clickEnd(e:Event):void {
                planeArray[nextPage].removeEventListener(page3D.OPEN_END, clickEnd);
                interactiveFlag=true;
                if (buttonFlag==true) {
                    template.view.buttonMode = true;
                }
                Mouse.show();
            }



            //プリミティブのロールオーバー、クリックを有効にする為
            //viewのbuttonModeとinteractiveをtrueにする
            template.view.buttonMode = true;
            template.view.interactive = true;

            // Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
            // レンダリング前に実行したい処理を記述します。
            template.onPreRender = function():void {

                // カメラの座標を中央に向かせる
                template.cameraContoller.lookAt(new Point3D());

            }

        }



    }
}





/*----------------------------------------------------------------------------------------*/


import alternativ5.engine3d.core.Object3D;
import alternativ5.engine3d.primitives.Box;
import alternativ5.engine3d.primitives.Plane;
import alternativ5.engine3d.events.MouseEvent3D
import alternativ5.engine3d.materials.FillMaterial;
import alternativ5.engine3d.materials.TextureMaterial;
import alternativ5.engine3d.materials.TextureMaterialPrecision
import alternativ5.types.Texture
import alternativ5.utils.MathUtils

import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.display.BitmapData;
import flash.display.BlendMode;

import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.*

import caurina.transitions.Tweener;


/**
 * ページクラス
 */
class page3D extends Object3D{
    public static const MOUSE_OVER:String = 'mouse_over';
    public static const MOUSE_OUT:String = 'mouse_out';
    public static const LEFT_CLICK:String = 'left_click';
    public static const RIGHT_CLICK:String = 'right_click';
    public static const OPEN_END:String = 'open_end';
    public static const CLOSE_END:String = 'close_end';
    
    private var colorArray:Array=[0xFF0000,0x0000FF,0x00FF00,0xFF00FF,0xFFFF00,0x00FFFF]
    private var colorCounter:Object={front:0,back:0}
    private var material:FillMaterial

    private var leftPage:Object3D
    private var rightPage:Object3D

    private var openTime:uint=1;
    private var side:String;
    private var id:uint;

    public function page3D(_id:uint,img:DisplayObject,_side:String=null):void {
        id=_id;
        var mt:Matrix = new Matrix()
        side=_side

        if (side!='back') {
            //左ページ、表紙作成
            leftPage = new Object3D()
            this.addChild(leftPage)
            var leftPlane:Plane=new Plane(img.width/2, img.height,1,1)
            leftPage.addChild(leftPlane)
            leftPlane.x=img.width/-4

            //左用materialの作成
            var leftImage:BitmapData
            var leftMaterial:TextureMaterial
            leftImage = new BitmapData(img.width/2, img.height, true, 0x00000000);

            leftMaterial = new TextureMaterial(new Texture(leftImage), 1, false, true, BlendMode.NORMAL, -1);
            //leftMaterial.precision = TextureMaterialPrecision.VERY_LOW;
            leftPlane.setMaterialToSurface(leftMaterial,'front')
            leftImage.draw(img);

            leftPlane.addEventListener(MouseEvent3D.MOUSE_OVER, onMouseOver);
            leftPlane.addEventListener(MouseEvent3D.MOUSE_OUT, onMouseOut);

        }


        if (side!='front') {
            //右ページの作成、裏表紙作成
            rightPage = new Object3D()
            this.addChild(rightPage)
            var rightPlane:Plane=new Plane(img.width/2, img.height,1,1)
            rightPage.addChild(rightPlane)
            rightPlane.x=img.width/4
            mt.translate(-img.width/2,0)

            //右用materialの作成
            var rightImage:BitmapData
            var rightMaterial:TextureMaterial

            rightImage = new BitmapData(img.width/2, img.height, true, 0x00000000);
            rightImage.draw(img,mt);
            rightMaterial = new TextureMaterial(new Texture(rightImage), 1, false, true, BlendMode.NORMAL, -1);
            //rightMaterial.precision = TextureMaterialPrecision.VERY_LOW;

            rightPage.rotationY=MathUtils.toRadian(-180)

            rightPlane.setMaterialToSurface(rightMaterial,'front')

            rightPlane.addEventListener(MouseEvent3D.MOUSE_OVER, onMouseOver);
            rightPlane.addEventListener(MouseEvent3D.MOUSE_OUT, onMouseOut);

        }


            //Planeにロールオーバー、クリックのリスナーを追加
        if (side=='front') {
            leftPlane.addEventListener(MouseEvent3D.CLICK, onLeftClick);

        } else if (side=='back') {
            rightPlane.addEventListener(MouseEvent3D.CLICK, onRightClick);

        } else {
            leftPlane.addEventListener(MouseEvent3D.CLICK, onLeftClick);
            rightPlane.addEventListener(MouseEvent3D.CLICK, onRightClick);
        }




    }

    /*-------------------------------------------------------
        ロールオーバー、クリック動作を設定
    -------------------------------------------------------*/
    private function onLeftClick(e:MouseEvent3D):void {
        var sid:Object=e.surface.id
        dispatchEvent(new Event(LEFT_CLICK))
    }

    private function onRightClick(e:MouseEvent3D):void {
        var sid:Object=e.surface.id
        dispatchEvent(new Event(RIGHT_CLICK))
    }

    private function onMouseOver(e:MouseEvent3D):void {
        var sid:Object=e.surface.id
        dispatchEvent(new Event(MOUSE_OVER))
    }

    private function onMouseOut(e:MouseEvent3D):void {
        var sid:Object=e.surface.id
        dispatchEvent(new Event(MOUSE_OUT))

    }


    /*-------------------------------------------------------
        ページがめくれる動作
    -------------------------------------------------------*/
    public function openLeft():void {
        if (leftPage) {
            if (leftPage.rotationY==MathUtils.toRadian(180)) {
                Tweener.addTween(leftPage, {rotationY:MathUtils.toRadian(0),time:openTime,transition:"linear", onComplete:endOpen});
            }
        }
    }

    public function openRight():void {
        if (rightPage) {
            if (rightPage.rotationY==MathUtils.toRadian(-180)) {
                Tweener.addTween(rightPage, {rotationY:MathUtils.toRadian(0),time:openTime,transition:"linear", onComplete:endOpen});
            }
        }
    }


    public function closeLeft():void {
        if (leftPage) {
            if (leftPage.rotationY==MathUtils.toRadian(0)) {
                Tweener.addTween(leftPage, {rotationY:MathUtils.toRadian(180),time:openTime,transition:"linear", onComplete:endClose});
            }
        }
    }

    public function closeRight():void {
        if (rightPage) {
            if (rightPage.rotationY==MathUtils.toRadian(0)) {
                Tweener.addTween(rightPage, {rotationY:MathUtils.toRadian(-180),time:openTime,transition:"linear", onComplete:endClose});
            }
        }
    }

    public function setIndex(maxPage:uint,pagePitch:Number,numZ:Number,numX:Number):void {
        var pz:Number=(maxPage-numZ)*pagePitch
        Tweener.addTween(this, {z:pz,time:openTime,transition:"linear"});
    }

    
    private function endOpen():void {
        dispatchEvent(new Event(OPEN_END))
    }

    private function endClose():void {
        dispatchEvent(new Event(CLOSE_END))
    }

    private function aRadian(radian:Number):Number {
        return radian/Math.PI*180
    }


}



/*----------------------------------------------------------------------------------------*/

import alternativ5.engine3d.controllers.CameraController;
import alternativ5.engine3d.core.Camera3D;
import alternativ5.engine3d.core.Object3D;
import alternativ5.engine3d.core.Scene3D;
import alternativ5.engine3d.display.View;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;


/**
 * BasicTemplate for Alternativa3D
 * Alternativa3Dを扱いやすくするためのテンプレートです
 * @author Yasu
 */
class BasicTemplate extends Sprite{
    /**
     * シーンインスタンスです。
     */
    public var scene:Scene3D;
    /**
     * ビューインスタンスです。
     */
    public var view:View;
    /**
     * カメラインスタンスです。
     */
    public var camera:Camera3D;
    /**
     * カメラコントローラーです。
     */
    public var cameraContoller:CameraController;
    
    private var _viewWidth:int;
    private var _viewHeight:int;
    private var _scaleToStage:Boolean;

    /**
     * 新しい BasicTemplate インスタンスを作成します。
     * @param    viewWidth
     * @param    viewHeight
     * @param    scaleToStage
     */
    public function BasicTemplate(viewWidth:int=640, viewHeight:int=480, scaleToStage:Boolean = true) {
        _viewWidth = viewWidth;
        _viewHeight = viewHeight;
        _scaleToStage = scaleToStage;
        
        // Creating scene
        scene = new Scene3D();
        scene.splitAnalysis = false; // not analysis for performance
        scene.root = new Object3D();
        
        // Adding camera
        camera = new Camera3D();
        camera.z = -1000;
        scene.root.addChild(camera);
        
        // camera contoller
        cameraContoller = new CameraController(this);
        cameraContoller.camera = camera;
        
        // set view
        view = new View();
        view.camera = camera;
        addChild(view);
        
        // stage
        if (stage) init();
        else addEventListener(Event.ADDED_TO_STAGE, init);
    }
    
    /**
     * 初期化されたときに実行されるイベントです。
     * 初期化時に実行したい処理をオーバーライドして記述します。
     */
    protected function atInit():void {}
    
    /**
     * 初期化されたときに実行されるイベントです。
     * 初期化時に実行したい処理を記述します。
     */
    private var _onInit:Function = function():void { };
    public function get onInit():Function { return _onInit; }
    public function set onInit(value:Function):void {
        _onInit = value;
    }
    
    /**
     * Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
     * レンダリング前に実行したい処理をオーバーライドして記述します。
     */
    protected function atPreRender():void {}
    
    /**
     * Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
     * レンダリング前に実行したい処理を記述します。
     */
    private var _onPreRender:Function = function():void{};
    public function get onPreRender():Function { return _onPreRender; }
    public function set onPreRender(value:Function):void {
        _onPreRender = value;
    }
    
    /**
     * Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
     * レンダリング後に実行したい処理をオーバーライドして記述します。
     */
    protected function atPostRender():void {
    }
    
    /**
     * Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
     * レンダリング後に実行したい処理を記述します。
     */
    protected var _onPostRender:Function = function():void{};
    public function get onPostRender():Function { return _onPostRender; }
    public function set onPostRender(value:Function):void {
        _onPostRender = value;
    }
    
    /**
     * レンダリングを開始します。
     */
    public function startRendering():void {
        addEventListener(Event.ENTER_FRAME, onRenderTick);
    }
    /**
     * レンダリングを停止します。
     */
    public function stopRendering():void {
        removeEventListener(Event.ENTER_FRAME, onRenderTick);
    }
    
    /**
     * シングルレンダリング(レンダリングを一回だけ)を実行します。
     */
    public function singleRender():void {
        onRenderTick();
    }
    
    /**
     * @private
     */
    private function init(e:Event = null):void {
        stage.scaleMode = StageScaleMode.NO_SCALE;
        stage.align = StageAlign.TOP_LEFT;
        stage.quality = StageQuality.HIGH;

        // resize
        stage.addEventListener(Event.RESIZE, onResize);
        onResize(null);
        
        // render
        startRendering();
        
        atInit();
        _onInit();
        
    }
    
    /**
     * @private
     */
    private function onRenderTick(e:Event = null):void {
        atPreRender();
        _onPreRender();
        scene.calculate();
        atPostRender();
        _onPostRender();
    }
    
    /**
     * @private
     */
    private function onResize(event:Event = null):void {
        if (_scaleToStage) {
            view.width = stage.stageWidth;
            view.height = stage.stageHeight;
        }else {
            view.width = _viewWidth;
            view.height = _viewHeight;
        }
    }
}






//---------------------------------------------------------------------------------
//自作カメラコントロール
//---------------------------------------------------------------------------------
import alternativ5.utils.KeyboardUtils
import flash.events.KeyboardEvent;
import flash.events.TimerEvent;
import flash.utils.Timer
import flash.ui.Mouse;


class rollingCameraController {

    private var camera:Camera3D;    

    private var angle:Number
    private var action:String=''
    private var zoom:Number=1
    private var parentMc:*;

    function rollingCameraController(_parent:*,stage:*,_camera:Camera3D,_zoom:Number=300,_angle:Number=-90):void {

        parentMc=_parent;            //親クラス
        camera = _camera;            //操作するカメラ

        angle=_angle
        zoom=_zoom

        stage.addEventListener(KeyboardEvent.KEY_DOWN, KeyDown);
        stage.addEventListener(KeyboardEvent.KEY_UP, KeyUp);

        parentMc.addEventListener(Event.ENTER_FRAME, onEnterFrame);

        /*
        var loopTimer:Timer = new Timer(50,0);
        var i=0

        loopTimer.addEventListener(TimerEvent.TIMER, onEnterFrame);
        loopTimer.start();

        */
        rollingCamera()
    }


    private function onEnterFrame(e:Event):void {
        if (action=='right') {
            angle+=1
            angle%=360
            rollingCamera()
        } else if (action=='left') {
            angle-=1
            angle%=360
            rollingCamera()
        } else if (action=='up') {
            camera.z+=10
            rollingCamera()
        } else if (action=='down') {
            camera.z-=10
            rollingCamera()
        } else if (action=='zoomIn') {
            zoom+=10
            rollingCamera()
        } else if (action=='zoomOut') {
            zoom-=10
            if (zoom<1) {
                zoom=1
            }
            rollingCamera()
            trace(zoom)

        } else if (action=='cameraOffsetXRight') {
            //parentMc.cameraOffsetX+=10

        } else if (action=='cameraOffsetXLeft') {
            //parentMc.cameraOffsetX-=10

        } else if (action=='cameraOffsetYUp') {
            //parentMc.cameraOffsetY+=10

        } else if (action=='cameraOffsetYDown') {
            //parentMc.cameraOffsetY-=10

        }
    }




    private function KeyDown(e:KeyboardEvent):void {
        switch (e.keyCode) {
            case KeyboardUtils.W:
            case KeyboardUtils.UP:
                action='up'
                break;

            case KeyboardUtils.S:
            case KeyboardUtils.DOWN:
                action='down'
                break;

            case KeyboardUtils.A:
            case KeyboardUtils.LEFT:
                action='left'
                break;

            case KeyboardUtils.D:
            case KeyboardUtils.RIGHT:
                action='right'
                break;

            case KeyboardUtils.Q:
            case KeyboardUtils.PAGE_UP:
                action='zoomIn'
                break;

            case KeyboardUtils.E:
            case KeyboardUtils.PAGE_DOWN:
                action='zoomOut'
                break;

            case KeyboardUtils.NUMPAD_8:
                action='cameraOffsetYUp'
                break;

            case KeyboardUtils.NUMPAD_2:
                action='cameraOffsetYDown'
                break;

            case KeyboardUtils.NUMPAD_4:
                action='cameraOffsetXLeft'
                break;

            case KeyboardUtils.NUMPAD_6:
                action='cameraOffsetXRight'
                break;

        }
    }

    private function Wheel(e:MouseEvent):void {
    }


    private function KeyUp(e:KeyboardEvent):void {
        action=''

    }

    public function rollingCamera():void {
        var radian:Number=angle/180*Math.PI;
        camera.x=Math.cos(radian)*zoom
        camera.y=Math.sin(radian)*zoom
        Mouse.show();
        
    }
    

}