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: Duck

import net.hires.debug.*;

Water 3D

・解説コメントをちょっと入れました

Click&Drag:Make wave

@author saharan
Get Adobe Flash player
by komaro 23 Oct 2012
/**
 * Copyright komaro ( http://wonderfl.net/user/komaro )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/6sah
 */

// forked from makc3d's Duck
// forked from keim_at_Si's Clear Water with refraction rendering forked from: 3D水面 / Water 3D
// forked from saharan's 3D水面 / Water 3D
package {
    import alternativ7.engine3d.core.Object3DContainer;
    import alternativ7.engine3d.core.RayIntersectionData;
    import alternativ7.engine3d.core.View;
    import alternativ7.engine3d.materials.TextureMaterial;
    import alternativ7.engine3d.objects.Mesh;
    import flash.geom.Matrix3D;
    import flash.geom.Vector3D;
    import flash.system.LoaderContext;
    import flash.display.*;
    import flash.events.*;
    import flash.net.*;
    import com.bit101.components.*;
    //import net.hires.debug.*;

    [SWF(frameRate = "30", width="465", height="465")]

    /**
     * Water 3D
     *
     * ・解説コメントをちょっと入れました
     * 
     * Click&Drag:Make wave
     * 
     * @author saharan
     */
    public class main extends Sprite {
        private const NUM_DETAILS:int = 48;
        private const INV_NUM_DETAILS:Number = 1 / NUM_DETAILS;
        private const MESH_SIZE:Number = 100;
        private var count:uint;
        private var bmd:BitmapData, bmd2:BitmapData;
        private var loader:Loader, loader2:Loader, loader3:Loader;
        private var vertices:Vector.<Vertex>;
        private var transformedVertices:Vector.<Number>;
        private var indices:Vector.<int>;
        private var uvt:Vector.<Number>, uvt2:Vector.<Number>;
        private var width2:Number;
        private var height2:Number;
        private var heights:Vector.<Vector.<Number>>;
        private var velocity:Vector.<Vector.<Number>>;
        private var press:Boolean;
        
        private var viewedAngle:Number = -65;
        private var focalLength:Number = 4 * MESH_SIZE;
        private var boxHeight:Number = MESH_SIZE * 0.75;
        private var refractiveIndex:Number = 1.4;
        private var reflectionLayer:Shape;
        private var refractionLayer:Shape;
        private var duckLayer:View;
        private var camera:BetterCamera3D;
        private var cameraDistance:Number = 1.02 * MESH_SIZE;
        private var duck:Mesh, plane:Mesh;
        private var duckNode:Object3DContainer;
        
        public function main():void {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }

        private function init(e:Event = null):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            stage.quality = StageQuality.LOW;
            width2 = 465 / 2;
            height2 = 465 / 2;
            // var s:Stats = new Stats();
            // s.alpha = 0.8;
            // addChild(s);
            count = 0;
            loader = new Loader();
            loader.load(new URLRequest("http://assets.wonderfl.net/images/related_images/b/b2/b217/b2177f87d979a28b9bcbb6e0b89370e77ce22337"), new LoaderContext(true));
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaded);
            loader2 = new Loader();
            loader2.load(new URLRequest("http://assets.wonderfl.net/images/related_images/b/bb/bbf1/bbf12c60cf84e5ab43e059920783d036da25df48"), new LoaderContext(true));
            loader2.contentLoaderInfo.addEventListener(Event.COMPLETE, loaded);
            loader3 = new Loader();
            loader3.load(new URLRequest("http://assets.wonderfl.net/images/related_images/b/ba/ba56/ba5643ab1dcece8b8f4eef06b44deedb31d6803c"), new LoaderContext(true));
            loader3.contentLoaderInfo.addEventListener(Event.COMPLETE, loaded);
            stage.addEventListener(MouseEvent.MOUSE_DOWN,
                function(e:Event = null):void {
                    drag();
                    press = true;
                });
            stage.addEventListener(MouseEvent.MOUSE_UP,
                function(e:Event = null):void {
                    press = false;
                });
            stage.addEventListener(MouseEvent.MOUSE_MOVE,
                function(e:Event = null):void {
                    if (press) drag();
                });
            vertices = new Vector.<Vertex>(NUM_DETAILS * NUM_DETAILS, true);
            transformedVertices = new Vector.<Number>(NUM_DETAILS * NUM_DETAILS * 2, true);
            indices = new Vector.<int>();
            uvt = new Vector.<Number>(NUM_DETAILS * NUM_DETAILS * 2, true);
            uvt2 = new Vector.<Number>(NUM_DETAILS * NUM_DETAILS * 2, true);
            var i:int;
            var j:int;
            // 頂点初期化。外側2つ分は表示しないので無駄な処理&メモリに・・・
            // 【modification】 nx, ny と整合性を取るために x-z 平面 ⇒ x-y 平面 に修正
            for (i = 2; i < NUM_DETAILS - 2; i++) {
                for (j = 2; j < NUM_DETAILS - 2; j++) {
                    vertices[getIndex(j, i)] = new Vertex(
                        (j - (NUM_DETAILS - 1) * 0.5) / NUM_DETAILS * MESH_SIZE,
                        (i - (NUM_DETAILS - 1) * 0.5) / NUM_DETAILS * MESH_SIZE, 0);
                    if (i != 2 && j != 2) {
                        indices.push(getIndex(i - 1, j - 1), getIndex(i, j - 1), getIndex(i, j));
                        indices.push(getIndex(i - 1, j - 1), getIndex(i, j), getIndex(i - 1, j));
                    }
                }
            }
            // 水面関係初期化
            heights = new Vector.<Vector.<Number>>(NUM_DETAILS, true);
            velocity = new Vector.<Vector.<Number>>(NUM_DETAILS, true);
            for (i = 0; i < NUM_DETAILS; i++) {
                heights[i] = new Vector.<Number>(NUM_DETAILS, true);
                velocity[i] = new Vector.<Number>(NUM_DETAILS, true);
                for (j = 0; j < NUM_DETAILS; j++) {
                    heights[i][j] = 0;
                    velocity[i][j] = 0;
                }
            }
            

            // I will not be writing my own engine for this code, sorry :(
            camera = new BetterCamera3D;
            camera.view = new View (465, 465);
            camera.view.hideLogo ();
            camera.f = focalLength;
            var dc:DuckContainer = new DuckContainer;
            dc.addChild (camera);
            dc.addChild (plane = dc.plane);
            dc.addChild (duckNode = new Object3DContainer);
            duckNode.addChild (duck = dc.duck);
            duck.rotationX = Math.PI;
            duck.scaleX = 0.5;
            duck.scaleY = 0.5;
            duck.scaleZ = 0.5;


            // 【modification】Rendering layers
            addChild(refractionLayer = new Shape());
            addChild(reflectionLayer = new Shape());
            reflectionLayer.alpha = 0.7;
            addChild(camera.view);
            // 【modification】controlers
            new HUISlider(this, 0, 0, "Angle", function(e:Event):void { viewedAngle = -e.target.value;syncAlternativa();}).setSliderParams(0, 89, 65);
            new HUISlider(this, 0, 20, "Refraction", function(e:Event):void { refractiveIndex = e.target.value;}).setSliderParams(1, 3, 1.4);
            new HUISlider(this, 0, 40, "Reflection", function(e:Event):void { reflectionLayer.alpha = e.target.value;}).setSliderParams(0, 1, 0.7);

            syncAlternativa ();
        }
        
        private function loaded(e:Event) : void {
            e.target.removeEventListener(e.type, arguments.callee);
            if (loader.content && loader2.content && loader3.content) {
                bmd  = Bitmap(loader.content).bitmapData;
                bmd2 = Bitmap(loader2.content).bitmapData;
                duck.setMaterialToAllFaces (new TextureMaterial (Bitmap(loader3.content).bitmapData));
                addEventListener(Event.ENTER_FRAME, frame);
            }
        }

        private function frame(e:Event = null):void {
            count++;
            move();
            setMesh();
            transformVertices();
            draw();
            drawDuck();
        }

        private function setMesh():void {
            // calclate constants
            var angle:Number = viewedAngle * 0.017453292519943295, 
                sin:Number = Math.sin(angle), 
                cos:Number = Math.cos(angle), 
                eyex:Number = 0, 
                eyey:Number = -sin * cameraDistance, 
                eyez:Number = -cos * cameraDistance,
                rimo:Number = refractiveIndex - 1,
                xymax:Number = MESH_SIZE * .45, //MESH_SIZE * 0.5,
                ixymax:Number = 1 / xymax;
            
            for (var i:int = 2; i < NUM_DETAILS - 2; i++) {
                for (var j:int = 2; j < NUM_DETAILS - 2; j++) {
                    const index:int = getIndex(i, j);
                    var v:Vertex = vertices[index];
                    v.z = heights[i][j] * 0.15;
                    
                    // ---Sphere map---
                    var nx:Number, ny:Number, nz:Number;
                    nx = (heights[i][j] - heights[i - 1][j]) * 0.15;
                    ny = (heights[i][j] - heights[i][j - 1]) * 0.15;
                    var len:Number = 1 / Math.sqrt(nx * nx + ny * ny + 1);
                    nx *= len;
                    ny *= len;
                    nz = len;
                    var tny:Number = cos * ny - sin * nz;
                    // it's all hacks
                    tny *= -1;
                    tny += 0.4 * tny * tny;
                    tny += 0.3;
                    uvt[index * 2] = tny * 0.5 + 0.5 + ((j - NUM_DETAILS * 0.5) * INV_NUM_DETAILS * 0.25);
                    uvt[index * 2 + 1] = nx * 0.5 + 0.5 + ((NUM_DETAILS * 0.5 - i) * INV_NUM_DETAILS * 0.25);
                    
                    // 【modification】 屈折マップ
                    
                    // ---Refraction map---
                    // incident vector (you can calculate them in the setup if you want faster)
                    var dx:Number = v.x - eyex, dy:Number = v.y - eyey, dz:Number = v.z - eyez;
                    len = 1 / Math.sqrt(dx * dx + dy * dy + dz * dz);
                    dx *= len;
                    dy *= len;
                    dz *= len;
                    // output vector
                    t = (dx * nx + dy * ny + dz) * rimo;
                    dx += nx * t;
                    dy += ny * t;
                    dz += nz * t;
                    // in this calculation, we can omit normalization of output vector !
                    //len = 1 / Math.sqrt(dx * dx + dy * dy + dz * dz);
                    //dx *= len;
                    //dy *= len;
                    //dz *= len;
                    // uv coordinate
                    var t:Number, s:Number, r:Number, hitz:Number, sign:Number;
                    if (dx == 0) {
                        if (dy == 0) {
                            uvt2[index * 2] = uvt2[index * 2 + 1] = 0.5;
                            sign = 0;
                        } else sign = (dy < 0) ? -1 : 1;
                    } else {
                        sign = (dx < 0) ? -1 : 1;
                        t = (sign * xymax - v.x) / dx;
                        s = t * dy + v.y;
                        if (-xymax < s && s < xymax) {
                            hitz = t * dz + v.z;
                            if (hitz > boxHeight) {
                                r = (boxHeight-v.z) / dz;
                                uvt2[index * 2]     = (dx * r + v.x) * ixymax * 0.25 + 0.5;
                                uvt2[index * 2 + 1] = (dy * r + v.y) * ixymax * 0.25 + 0.5;
                            } else {
                                r = boxHeight / (hitz + boxHeight);
                                uvt2[index * 2]     = sign       * r * 0.5 + 0.5;
                                uvt2[index * 2 + 1] = s * ixymax * r * 0.5 + 0.5;
                            }
                            sign = 0;
                        } else sign = (s < 0) ? -1 : 1;
                    }
                    if (sign != 0) {
                        t = (sign * xymax - v.y) / dy;
                        s = t * dx + v.x;
                        hitz = t * dz + v.z;
                        if (hitz > boxHeight) {
                            r = (boxHeight-v.z) / dz;
                            uvt2[index * 2]     = (dx * r + v.x) * ixymax * 0.25 + 0.5;
                            uvt2[index * 2 + 1] = (dy * r + v.y) * ixymax * 0.25 + 0.5;
                        } else {
                            r = boxHeight / (hitz + boxHeight);
                            uvt2[index * 2]     = s * ixymax * r * 0.5 + 0.5;
                            uvt2[index * 2 + 1] = sign       * r * 0.5 + 0.5;
                        }
                    }
                    //trace(v.x,v.y,dx,dy,uvt2[index * 2],uvt2[index * 2+1]);
                }
            }
            //throw new Error("STOPPER!!");
        }

        public function move():void {
            
            // ---Water simulation---
            
            var i:int;
            var j:int;
            var mx:Number = mouseX / 465 * NUM_DETAILS;
            var my:Number = (1 - mouseY / 465) * NUM_DETAILS;
            for (i = 1; i < NUM_DETAILS - 1; i++) {
                for (j = 1; j < NUM_DETAILS - 1; j++) {
                    heights[i][j] += velocity[i][j];
                    if (heights[i][j] > 100) heights[i][j] = 100;
                    else if (heights[i][j] < -100) heights[i][j] = -100;
                }
            }
            for (i = 1; i < NUM_DETAILS - 1; i++) {
                for (j = 1; j < NUM_DETAILS - 1; j++) {
                    velocity[i][j] = (velocity[i][j] +
                        (heights[i - 1][j] + heights[i][j - 1] + heights[i + 1][j] +
                        heights[i][j + 1] - heights[i][j] * 4) * 0.5) * 0.95;
                }
            }
        }

        public function drag():void {
            var i:int;
            var j:int;
            // do fucking ray-plane intersection, dammit!
            var o:Vector3D = new Vector3D (camera.x, camera.y, camera.z);
            var d:Vector3D = o.clone ();
            d.normalize (); d.scaleBy ( -1);
            var n:Vector3D = d.clone ();
            n.y = - d.z; n.z = d.y;
            d.scaleBy (focalLength);
            n.scaleBy (232.5 - mouseY);
            d.incrementBy (n);
            d.x += mouseX - 232.5;
            var data:RayIntersectionData = plane.intersectRay (o, d);
            if (data == null) return;
            //duck.x = data.point.x;
            //duck.y = data.point.y;
            var mx:int = NUM_DETAILS * (data.point.x + 0.5 * MESH_SIZE) / MESH_SIZE;
            var my:int = NUM_DETAILS * (data.point.y + 0.5 * MESH_SIZE) / MESH_SIZE;
            for (i = mx - 3; i < NUM_DETAILS - 1 && mx + 3; i++) {
                for (j = my - 3; j < NUM_DETAILS - 1 && my + 3; j++) {
                    if (i > 1 && j > 1 && i < NUM_DETAILS - 1 && j < NUM_DETAILS - 1) {
                        var len:Number = 3 - Math.sqrt((mx - i) * (mx - i) + (my - j) * (my - j));
                        if (len < 0) len = 0;
                        velocity[i][j] -= len * (press ? 1 : 5);
                    }
                }
            }
        }

        private function draw():void {
            var refractionGraphics:Graphics = refractionLayer.graphics,
                reflectionGraphics:Graphics = reflectionLayer.graphics;
            graphics.clear();
            graphics.beginFill(0x202020);
            graphics.drawRect(0, 0, 465, 465);
            graphics.endFill();
            // 【modification】 屈折マップ
            refractionGraphics.clear();
            refractionGraphics.beginBitmapFill(bmd2);
            refractionGraphics.drawTriangles(transformedVertices, indices, uvt2, TriangleCulling.NEGATIVE);
            refractionGraphics.endFill();
            reflectionGraphics.clear();
            reflectionGraphics.beginBitmapFill(bmd);
            reflectionGraphics.drawTriangles(transformedVertices, indices, uvt, TriangleCulling.NEGATIVE);
            reflectionGraphics.endFill();
        }

        private function getIndex(x:int, y:int):int {
            return y * NUM_DETAILS + x;
        }

        private function transformVertices():void {
            
            // x軸回転とビュー変換・プロジェクション変換を実行
            
            var angle:Number = viewedAngle * Math.PI / 180;
            var sin:Number = Math.sin(angle);
            var cos:Number = Math.cos(angle);
            for (var i:int = 0; i < vertices.length; i++) {
                var v:Vertex = vertices[i];
                if(v != null) {
                    var x:Number = v.x;
                    // x軸回転行列もどき
                    var y:Number = cos * v.y - sin * v.z;
                    var z:Number = sin * v.y + cos * v.z;
                    // wtf, people, why can't we have
                    // normal pinhole projection here
                    z = focalLength / (z + cameraDistance);
                    x = x * z + 232.5;
                    y = y * z + 232.5;
                    transformedVertices[i * 2] = x;
                    transformedVertices[i * 2 + 1] = y;
                }
            }
        }

        private function syncAlternativa ():void {
            var a:Number = viewedAngle * Math.PI / 180;
            camera.rotationX = -a;
            camera.y = -Math.sin (a) * cameraDistance;
            camera.z = -Math.cos (a) * cameraDistance;
        }

        private var duckVelocityX:Number = 0;
        private var duckVelocityY:Number = 0;
        private var duckSpin:Number = 0;

        private function drawDuck ():void {
            var duckX:Number = duckNode.x;
            var duckY:Number = duckNode.y;
            var i:int = NUM_DETAILS * (duckX + 0.5 * MESH_SIZE) / MESH_SIZE;
            var j:int = NUM_DETAILS * (duckY + 0.5 * MESH_SIZE) / MESH_SIZE;
            i = Math.min (NUM_DETAILS - 2, Math.max (1, i));
            j = Math.min (NUM_DETAILS - 2, Math.max (1, j));
            var duckZ:Number = heights[i][j] * 0.15;

            // water normal (idea stolen from reflection code,
            // so I'm not even sure this is correct formula :)
            var n:Vector3D = new Vector3D (
                (heights[i + 1][j] - heights[i - 1][j]) * 0.075,
                (heights[i][j + 1] - heights[i][j - 1]) * 0.075,
                1
            ); n.normalize ();

            // duck tilt matrix corresponding to this normal
            var m:Matrix3D = new Matrix3D;
            var r:Vector3D = n.crossProduct (Vector3D.Z_AXIS);
            if (r.length > 0.00001) {
                r.normalize ();
                m.prependRotation (
                    Math.acos (n.dotProduct (Vector3D.Z_AXIS)) * 180 / Math.PI,
                    r
                );
            }

            duckNode.matrix = m;

            duckNode.x = duckX + duckVelocityX;
            duckNode.y = duckY + duckVelocityY;
            duckNode.z = duckZ;

            duck.rotationZ +=  duckSpin;

            camera.render ();

            // drift
            duckVelocityX += 0.05 * n.x;
            duckVelocityY += 0.05 * n.y;

            // bounce
            if (((i == 1) && (duckVelocityX < 0)) || ((i == NUM_DETAILS - 2) && (duckVelocityX > 0))) duckVelocityX *= -1;
            if (((j == 1) && (duckVelocityY < 0)) || ((j == NUM_DETAILS - 2) && (duckVelocityY > 0))) duckVelocityY *= -1;

            // spin... I actually have no fucking idea how to calculate it correctly :(
            duckSpin += 0.015 * (velocity [i + 1][j + 1] - velocity [i][j] + velocity [i + 1][j] - velocity [i][j + 1]);
            duckSpin *= 0.999;
        }
    }
}

class Vertex {
    public var x:Number;
    public var y:Number;
    public var z:Number;

    public function Vertex(x:Number, y:Number,z:Number) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}


import alternativ7.engine3d.alternativa3d;
import alternativ7.engine3d.core.Camera3D;
/** How hard is it to make focalLength a property? */
class BetterCamera3D extends Camera3D {
    public function get f ():Number {
        if (view != null) {
            alternativa3d::viewSizeX = view.alternativa3d::_width * 0.5;
            alternativa3d::viewSizeY = view.alternativa3d::_height * 0.5;
            alternativa3d::focalLength = Math.sqrt (
                ((alternativa3d::viewSizeX * alternativa3d::viewSizeX) +
                 (alternativa3d::viewSizeY * alternativa3d::viewSizeY))
            ) / Math.tan (fov * 0.5);
        }
        return alternativa3d::focalLength;
    }
    public function set f (v:Number):void {
        if ((view != null) && (v > 0)) {
            alternativa3d::viewSizeX = view.alternativa3d::_width * 0.5;
            alternativa3d::viewSizeY = view.alternativa3d::_height * 0.5;
            fov = 2 * Math.atan2 (Math.sqrt (
                ((alternativa3d::viewSizeX * alternativa3d::viewSizeX) +
                 (alternativa3d::viewSizeY * alternativa3d::viewSizeY))
            ), v);
        }
    }
}

import alternativ7.engine3d.core.Object3DContainer;
import alternativ7.engine3d.loaders.Parser3DS;
import alternativ7.engine3d.materials.FillMaterial;
import alternativ7.engine3d.objects.Mesh;
import alternativ7.engine3d.primitives.Plane;
import flash.utils.ByteArray;
class DuckContainer extends Object3DContainer {
    public var duck:Mesh;
    public var plane:Plane;
    public function DuckContainer () {
        super ();

        plane = new Plane (90, 90);
        plane.setMaterialToAllFaces (new FillMaterial (0, 0, 1, 0xFFFF00));

        var parser:Parser3DS = new Parser3DS;
        parser.parse (new Base64 (duck64.toString ()));
        duck = Mesh (parser.objects [0]);
    }
    private var duck64:XML = <duck>
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
Ps+/RT9GJNI+6KJBP9yDHD/Pv0U/RiTSPu+pVD/2YSk/5KNhPzJWkz64kF8/RfQnP++pVD/2YSk/
5KNhPzJWkz7vqVQ/9mEpP6OVVz/Sx5Q+o5VXP9LHlD7vqVQ/9mEpP8+/RT9GJNI+z79FP0Yk0j6Y
/D8/UAxJPqOVVz/Sx5Q+OXtDPxgFAT6Y/D8/UAxJPulJJT/gnfU97gV2PjCl/j6fW5g+utu9PvGc
tT6lvgA/8Zy1PqW+AD+fW5g+utu9Pk0V/D5EGqU+TRX8PkQapT4e//U+hXoKP/GctT6lvgA/7gV2
PjCl/j7VXJ4+oPwRPyPzkD5aRxU/1VyePqD8ET+srJ0+Lo4ePyPzkD5aRxU/2DJJPldBKD8M5h8+
QE4wP4iPyD2ZKA4/gOxFPmXFQD8M5h8+QE4wP9gyST5XQSg/xLRvPnB6Rz+A7EU+ZcVAP9gyST5X
QSg/2DJJPldBKD+Ij8g9mSgOP9odcj5eESQ/2DJJPldBKD/aHXI+XhEkP8S0bz5wekc/7gV2PjCl
/j7xnLU+pb4AP9Vcnj6g/BE/Y0fbPvkTbT8qGZA+QL5cP6pgvD6vPk4/5kAPPwskWD9jR9s++RNt
Pxv26z5tyU4/dm0TPw6fMD/mQA8/CyRYP1rVAj+95T4/K/wFP3B7Dj92bRM/Dp8wP4LGBD8Ulx8/
IoqBPsLDTD+srJ0+Lo4eP/rxpz4tYDo/KhmQPkC+XD8iioE+wsNMP/rxpz4tYDo/vf/fPjgwET/x
nLU+pb4APx7/9T6Fego/+vGnPi1gOj+qYLw+rz5OPyoZkD5Avlw/Y0fbPvkTbT+qYLw+rz5OPxv2
6z5tyU4/5kAPPwskWD8b9us+bclOP1rVAj+95T4/dm0TPw6fMD9a1QI/veU+P4LGBD8Ulx8/gsYE
PxSXHz8e//U+hXoKPyv8BT9wew4/Hv/1PoV6Cj+CxgQ/FJcfP73/3z44MBE/rKydPi6OHj/VXJ4+
oPwRP/GctT6lvgA/00zfPtJvKz/68ac+LWA6P6ysnT4ujh4/qmC8Pq8+Tj/68ac+LWA6P9NM3z7S
bys/00zfPtJvKz8b9us+bclOP6pgvD6vPk4/00zfPtJvKz9a1QI/veU+Pxv26z5tyU4/00zfPtJv
Kz+CxgQ/FJcfP1rVAj+95T4/00zfPtJvKz+9/98+ODARP4LGBD8Ulx8/rKydPi6OHj+9/98+ODAR
P9NM3z7Sbys/vf/fPjgwET+srJ0+Lo4eP/GctT6lvgA/o5VXP9LHlD6Y/D8/UAxJPjl7Qz8YBQE+
o5VXP9LHlD45e0M/GAUBPuSjYT8yVpM+MbR+PwBkrjvko2E/MlaTPjl7Qz8YBQE+MbR+PwBkrjs5
e0M/GAUBPmsMFj9YZoo9awwWP1hmij3F/8U+YMKIPT9zvj4AYac7P3O+PgBhpzsxtH4/AGSuO2sM
Fj9YZoo9mPw/P1AMST7pSSU/4J31PX6PLj9oNk8+YK0KP8DWNT7pSSU/4J31PYgs+j5g5/89YK0K
P8DWNT6ILPo+YOf/PS+L4T64hmk+6UklP+Cd9T1grQo/wNY1Pn6PLj9oNk8+TRX8PkQapT5u3Rk/
xhiwPqm8BT8a+JE+qbwFPxr4kT4vi+E+uIZpPk0V/D5EGqU+L4vhPriGaT6pvAU/GviRPmCtCj/A
1jU+O3MzPyamqz6pvAU/GviRPm7dGT/GGLA+bt0ZP8YYsD7Pv0U/RiTSPjtzMz8mpqs+z79FP0Yk
0j6Y/D8/UAxJPjtzMz8mpqs+O3MzPyamqz5grQo/wNY1Pqm8BT8a+JE+fo8uP2g2Tz47czM/Jqar
Ppj8Pz9QDEk+YK0KP8DWNT47czM/JqarPn6PLj9oNk8+pPVXPtArbj6gSUI+NA/APl9+hz6MQlI+
X36HPoxCUj6gSUI+NA/APp9bmD66270+P3O+PgBhpzuk9Vc+0CtuPl9+hz6MQlI+X36HPoxCUj7F
/8U+YMKIPT9zvj4AYac7iCz6PmDn/z1rDBY/WGaKPcX/xT5gwog9awwWP1hmij2ILPo+YOf/PelJ
JT/gnfU9OXtDPxgFAT5rDBY/WGaKPelJJT/gnfU9xf/FPmDCiD0vi+E+uIZpPogs+j5g5/89X36H
PoxCUj4vi+E+uIZpPsX/xT5gwog97gV2PjCl/j6fW5g+utu9PqBJQj40D8A+L4vhPriGaT5ffoc+
jEJSPp9bmD66270+TRX8PkQapT4vi+E+uIZpPp9bmD66270+K/wFP3B7Dj9NFfw+RBqlPh7/9T6F
ego/bt0ZP8YYsD5NFfw+RBqlPiv8BT9wew4/bt0ZP8YYsD4r/AU/cHsOP+iiQT/cgxw/76lUP/Zh
KT/hDE4/dcg1P7iQXz9F9Cc/76lUP/ZhKT/ookE/3IMcP+EMTj91yDU/z79FP0Yk0j5u3Rk/xhiw
PuiiQT/cgxw/76lUP/ZhKT/Pv0U/RiTSPuiiQT/cgxw/76lUP/ZhKT+4kF8/RfQnP+SjYT8yVpM+
o5VXP9LHlD7vqVQ/9mEpP+SjYT8yVpM+z79FP0Yk0j7vqVQ/9mEpP6OVVz/Sx5Q+o5VXP9LHlD6Y
/D8/UAxJPs+/RT9GJNI+6UklP+Cd9T2Y/D8/UAxJPjl7Qz8YBQE+8Zy1PqW+AD+fW5g+utu9Pu4F
dj4wpf4+TRX8PkQapT6fW5g+utu9PvGctT6lvgA/8Zy1PqW+AD8e//U+hXoKP00V/D5EGqU+I/OQ
PlpHFT/VXJ4+oPwRP+4Fdj4wpf4+I/OQPlpHFT+srJ0+Lo4eP9Vcnj6g/BE/iI/IPZkoDj8M5h8+
QE4wP9gyST5XQSg/2DJJPldBKD8M5h8+QE4wP4DsRT5lxUA/2DJJPldBKD+A7EU+ZcVAP8S0bz5w
ekc/2h1yPl4RJD+Ij8g9mSgOP9gyST5XQSg/xLRvPnB6Rz/aHXI+XhEkP9gyST5XQSg/1VyePqD8
ET/xnLU+pb4AP+4Fdj4wpf4+qmC8Pq8+Tj8qGZA+QL5cP2NH2z75E20/G/brPm3JTj9jR9s++RNt
P+ZADz8LJFg/WtUCP73lPj/mQA8/CyRYP3ZtEz8OnzA/gsYEPxSXHz92bRM/Dp8wPyv8BT9wew4/
+vGnPi1gOj+srJ0+Lo4ePyKKgT7Cw0w/+vGnPi1gOj8iioE+wsNMPyoZkD5Avlw/Hv/1PoV6Cj/x
nLU+pb4AP73/3z44MBE/KhmQPkC+XD+qYLw+rz5OP/rxpz4tYDo/G/brPm3JTj+qYLw+rz5OP2NH
2z75E20/WtUCP73lPj8b9us+bclOP+ZADz8LJFg/gsYEPxSXHz9a1QI/veU+P3ZtEz8OnzA/K/wF
P3B7Dj8e//U+hXoKP4LGBD8Ulx8/vf/fPjgwET+CxgQ/FJcfPx7/9T6Fego/8Zy1PqW+AD/VXJ4+
oPwRP6ysnT4ujh4/rKydPi6OHj/68ac+LWA6P9NM3z7Sbys/00zfPtJvKz/68ac+LWA6P6pgvD6v
Pk4/qmC8Pq8+Tj8b9us+bclOP9NM3z7Sbys/G/brPm3JTj9a1QI/veU+P9NM3z7Sbys/WtUCP73l
Pj+CxgQ/FJcfP9NM3z7Sbys/gsYEPxSXHz+9/98+ODARP9NM3z7Sbys/00zfPtJvKz+9/98+ODAR
P6ysnT4ujh4/8Zy1PqW+AD+srJ0+Lo4eP73/3z44MBE/OXtDPxgFAT6Y/D8/UAxJPqOVVz/Sx5Q+
5KNhPzJWkz45e0M/GAUBPqOVVz/Sx5Q+OXtDPxgFAT7ko2E/MlaTPjG0fj8AZK47awwWP1hmij05
e0M/GAUBPjG0fj8AZK47P3O+PgBhpzvF/8U+YMKIPWsMFj9YZoo9awwWP1hmij0xtH4/AGSuOz9z
vj4AYac7IEEHBgAAmAAAAAEAAgAGAAMABAAFAAYABgAHAAgABgAJAAoACwAGAAwADQAOAAYADwAQ
ABEABgASABMAFAAGABUAFgAXAAYAGAAZABoABgAbABwAHQAGAB4AHwAgAAYAIQAiACMABgAkACUA
JgAGACcAKAApAAYAKgArACwABgAtAC4ALwAGADAAMQAyAAYAMwA0ADUABgA2ADcAOAAGADkAOgA7
AAYAPAA9AD4ABgA/AEAAQQAGAEIAQwBEAAYARQBGAEcABgBIAEkASgAGAEsATABNAAYATgBPAFAA
BgBRAFIAUwAGAFQAVQBWAAYAVwBYAFkABgBaAFsAXAAGAF0AXgBfAAYAYABhAGIABgBjAGQAZQAG
AGYAZwBoAAYAaQBqAGsABgBsAG0AbgAGAG8AcABxAAYAcgBzAHQABgB1AHYAdwAGAHgAeQB6AAYA
ewB8AH0ABgB+AH8AgAAGAIEAggCDAAYAhACFAIYABgCHAIgAiQAGAIoAiwCMAAYAjQCOAI8ABgCQ
AJEAkgAGAJMAlACVAAYAlgCXAJgABgCZAJoAmwAGAJwAnQCeAAYAnwCgAKEABgCiAKMApAAGAKUA
pgCnAAYAqACpAKoABgCrAKwArQAGAK4ArwCwAAYAsQCyALMABgC0ALUAtgAGALcAuAC5AAYAugC7
ALwABgC9AL4AvwAGAMAAwQDCAAYAwwDEAMUABgDGAMcAyAAGAMkAygDLAAYAzADNAM4ABgDPANAA
0QAGANIA0wDUAAYA1QDWANcABgDYANkA2gAGANsA3ADdAAYA3gDfAOAABgDhAOIA4wAGAOQA5QDm
AAYA5wDoAOkABgDqAOsA7AAGAO0A7gDvAAYA8ADxAPIABgDzAPQA9QAGAPYA9wD4AAYA+QD6APsA
BgD8AP0A/gAGAP8AAAEBAQYAAgEDAQQBBgAFAQYBBwEGAAgBCQEKAQYACwEMAQ0BBgAOAQ8BEAEG
ABEBEgETAQYAFAEVARYBBgAXARgBGQEGABoBGwEcAQYAHQEeAR8BBgAgASEBIgEGACMBJAElAQYA
JgEnASgBBgApASoBKwEGACwBLQEuAQYALwEwATEBBgAyATMBNAEGADUBNgE3AQYAOAE5AToBBgA7
ATwBPQEGAD4BPwFAAQYAQQFCAUMBBgBEAUUBRgEGAEcBSAFJAQYASgFLAUwBBgBNAU4BTwEGAFAB
UQFSAQYAUwFUAVUBBgBWAVcBWAEGAFkBWgFbAQYAXAFdAV4BBgBfAWABYQEGAGIBYwFkAQYAZQFm
AWcBBgBoAWkBagEGAGsBbAFtAQYAbgFvAXABBgBxAXIBcwEGAHQBdQF2AQYAdwF4AXkBBgB6AXsB
fAEGAH0BfgF/AQYAgAGBAYIBBgCDAYQBhQEGAIYBhwGIAQYAiQGKAYsBBgCMAY0BjgEGAI8BkAGR
AQYAkgGTAZQBBgCVAZYBlwEGAJgBmQGaAQYAmwGcAZ0BBgCeAZ8BoAEGAKEBogGjAQYApAGlAaYB
BgCnAagBqQEGAKoBqwGsAQYArQGuAa8BBgCwAbEBsgEGALMBtAG1AQYAtgG3AbgBBgC5AboBuwEG
ALwBvQG+AQYAvwHAAcEBBgDCAcMBxAEGAMUBxgHHAQYAMEE/AQAAcnViYmVyAJgAAAABAAIAAwAE
AAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAA
IQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9
AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkA
WgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2
AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIA
kwCUAJUAlgCXAA==</duck>;
}
// base64 code by 2ndyofyyx,
// http://wonderfl.kayac.com/code/b3a19884080f5ed34137e52e7c3032f3510ef861
import flash.utils.ByteArray; 
class Base64 extends ByteArray { 
    private static const BASE64:Array = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62,0,0,0,63,52,53,54,55,56,57,58,59,60,61,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,0,0,0,0,0,0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,0,0,0,0,0]; 
    public function Base64(str:String) { 
        var n:int, j:int; 
        for(var i:int = 0; i < str.length && str.charAt(i) != "="; i++) {
            if (str.charCodeAt (i) < 33) continue;
            j = (j << 6) | BASE64[str.charCodeAt(i)]; 
            n += 6; 
            while(n >= 8) { 
                writeByte((j >> (n -= 8)) & 0xFF); 
            } 
        } 
        position = 0; 
    } 
}