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

Rubber Ducky ♪

rubber ducky song from http://www.youtube.com/watch?v=Mh85R-S-dh8
Get Adobe Flash player
by yonatan 23 Oct 2012
  • Forked from makc3d's Duck
  • Diff: 234
  • Related works: 22
  • Talk

    makc3d at 13 Apr 2011 15:58
    someone should add crosshair and shotgun sound
    makc3d at 13 Apr 2011 18:25
    good idea to rotate reflection map 90 degrees, but I still think it should scroll somehow when you change angle
    yonatan at 13 Apr 2011 18:31
    i didn't even notice the 90 degree thing, but i messed up the ray-plane intersection :( i'll fix it...
    makc3d at 13 Apr 2011 18:49
    no, wait... I want to copy it :)
    makc3d at 13 Apr 2011 18:50
    I mean 90 degrees thing
    yonatan at 13 Apr 2011 18:54
    don't worry, i still have no idea what you are talking about with this while 90 degree thing. but the fucking intersection works now.
    makc3d at 13 Apr 2011 18:55
    oh wait, it is not the texture rotated, it's the whole thing :( nvm then
    esimov at 13 Apr 2011 19:42
    i don't take a look into the code, but what's the difference between your's and makc3d version? i see there is a slightly different effect on how the duck is reacting to the wave effect. anyway good competition :)
    makc3d at 13 Apr 2011 19:51
    @esimov his original change was added soundtrack from youtube. then keim modified his version, then yonatan - his, and now I modified mine, so it all turned into terrible mess
    esimov at 13 Apr 2011 21:21
    ohhh...there is a soundtrack too!? i didn't notice :)
    makc3d at 15 Apr 2011 15:57
    btw, yonatan, you forgot to swap x and y in var n:Vector3D = .. so now ducky tilt is wrong
    yonatan at 15 Apr 2011 16:06
    doh! i knew something wasn't right there. thanks.

    Tags

    Embed
/**
 * Copyright yonatan ( http://wonderfl.net/user/yonatan )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/oHoJ
 */

// 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 flash.system.*;
    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, loader4:Loader;
		private var player:Object;
        private var vertices:Vector.<Vector3D>;
        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 = -20;
        private var focalLength:Number = 4 * MESH_SIZE;

        private var viewedAngleH:Number = 0;
        private var viewedAngleV:Number = -20 * 0.017453292519943295;
        //private var focalLength:Number = MESH_SIZE * 4;
        private var boxHeight:Number = MESH_SIZE*0.75;
        private var refractiveIndex:Number = 1.4;
        private var reflectionLayer:Shape;
        private var refractionLayer:Shape;
        private var cameraPosition:Vector3D = new Vector3D();
        private var m00:Number, m01:Number, m02:Number, m10:Number, m11:Number, m12:Number, m20:Number, m21:Number, m22:Number;

		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);
			// tube
			Security.allowDomain("www.youtube.com");
            loader4 = new Loader();
            loader4.load(new URLRequest("http://www.youtube.com/apiplayer?version=3"));
            loader4.contentLoaderInfo.addEventListener(Event.COMPLETE, function(e:*):void {
					loader4.content.addEventListener("onReady", function(e:*):void {
							player = loader4.content;
							player.loadVideoById("Mh85R-S-dh8", 28);
						});
				});
			stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
            vertices = new Vector.<Vector3D>(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 Vector3D(
                        (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.4;
            addChild(camera.view);
            // 【modification】controlers
			new HUISlider(this, 0, 0, "Angle", function(e:Event):void { 
					viewedAngleV = -e.target.value* 0.017453292519943295; // keim
					viewedAngle = -e.target.value;syncAlternativa(); // makc
			}).setSliderParams(0, 80, 20);
            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.4);

			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 mouseDown(e:MouseEvent) : void {
            stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseDrag);
            ripple(5);
        }
        
        private function mouseUp(e:MouseEvent) : void {
            stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUp);
            stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseDrag);
        }
        
        private function mouseDrag(e:MouseEvent) : void {
            ripple(2);
        }
        
        private function ripple(intensity:Number) : void {
			// 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;

            var mx:Number = data.point.y; // flip them because of 90-degree rotation
            var my:Number = data.point.x;

            var i:int, j:int, dx:Number, dy:Number, acc:Number, imin:int, jmin:int, imax:int, jmax:int;
            mx = (mx / MESH_SIZE + 0.5) * NUM_DETAILS;
            my = (my / MESH_SIZE + 0.5) * NUM_DETAILS;
            imin = (mx > 5) ? int(mx - 3) : 2;
            jmin = (my > 5) ? int(my - 3) : 2;
            imax = (mx < NUM_DETAILS-5) ? int(mx + 4) : (NUM_DETAILS - 1);
            jmax = (my < NUM_DETAILS-5) ? int(my + 4) : (NUM_DETAILS - 1);
            for (i=imin; i<imax; i++) for (j=jmin; j<jmax; j++) {
                dx = mx - i;
                dy = my - j;
                acc = 3 - Math.sqrt(dx * dx + dy * dy);
                if (acc > 0) velocity[i][j] += acc*intensity;
            }
        }
        
    //-------------------------------------------------- on each frame
        private function frame(e:Event = null):void {
            count++;
            move();
            setMesh();
            transformVertices();
            draw();
            drawDuck();
        }

        private function move():void {
            // ---Water simulation---
            var i:int;
            var j:int;
            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;
                }
            }
            
            // why dont I use Matrix3D !?
//            var viewedAngleH:Number =   (mouseX -232.5) / 465 * 40 * 0.017453292519943295,
//                viewedAngleV:Number = -((mouseY -232.5) / 465 * 40 + 40) * 0.017453292519943295;
            var sx:Number = Math.sin(viewedAngleV), sy:Number = Math.sin(viewedAngleH), 
                cx:Number = Math.cos(viewedAngleV), cy:Number = Math.cos(viewedAngleH);
            m00 = cy;
            m01 = 0;
            m02 = -sy;
            m10 = sy*sx;
            m11 = cx;
            m12 = cy*sx;
            m20 = sy*cx;
            m21 = -sx;
            m22 = cy*cx;
            cameraPosition.x = -cameraDistance * m02;
            cameraPosition.y = -cameraDistance * m12;
            cameraPosition.z = -cameraDistance * m22;
        }

        private function setMesh():void {
            // calclate constants
            var rimo:Number = refractiveIndex - 1,
                xymax:Number = MESH_SIZE * 0.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 = i * NUM_DETAILS + j;
                    var v:Vector3D = 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;
                    // ちょっと式を変更して平面でもテクスチャが見えるように
                    uvt[index * 2] = nx * 0.5 + 0.5 + ((i - NUM_DETAILS * 0.5) * INV_NUM_DETAILS * 0.25);
                    uvt[index * 2 + 1] = ny * 0.5 + 0.5 + ((NUM_DETAILS * 0.5 - j) * 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 - cameraPosition.x, dy:Number = v.y - cameraPosition.y, dz:Number = v.z - cameraPosition.z;
                    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!!");
        }

        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 {
            var iz:Number, v:Vector3D, i:int, imax:int = vertices.length;
            for (i = 0; i < imax; i++) {
                v = vertices[i];
                if (v != null) {
                    iz = focalLength / (v.x * m02 + v.y * m12 + v.z * m22 + cameraDistance);
                    transformedVertices[i*2]   = (v.x * m00 + v.y * m10 + v.z * m20) * iz + 232.5;
                    transformedVertices[i*2+1] = (v.x * m01 + v.y * m11 + v.z * m21) * iz + 232.5;
                }
            }
        }

		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.y;
			var duckY:Number = duckNode.x;
            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][j + 1] - heights[i][j - 1]) * 0.075,
				(heights[i + 1][j] - heights[i - 1][j]) * 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.y = duckX + duckVelocityX;
			duckNode.x = 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;
		}
    }
}


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; 
    } 
}