public static AvalonSoundChannel ToSound(this string asset)
        {
            var a = new IHTMLAudio { src = asset, autobuffer = true };


            a.AttachToDocument();
            //a.style.display = IStyle.DisplayEnum.none;

            // we can now use HTML5 audio element
            var x = new AvalonSoundChannel
            {

                Start =
                    delegate
                    {
                        a.play();
                    },

                Stop =
                    delegate
                    {
                        a.pause();

                    }
            };

            a.onended +=
                delegate
                {
                    x.RaisePlaybackComplete();
                };


            return x;
        }
        public void Play()
        {
            //this.ToTrace();

            if (this.InternalAudio == null)
            {
                if (this.Audio != null)
                    this.InternalAudio = this.Audio();
            }

            if (this.InternalAudio == null)
                return;

            this.InternalAudio.play();
            this.InternalAudio = this.Audio();
            this.InternalAudio.load();

        }
        /// <summary>
        /// This is a javascript application.
        /// </summary>
        /// <param name="page">HTML document rendered by the web server which can now be enhanced.</param>
        public Application(IApp page)
        {
            Func<IHTMLAudio, Action<double>> loop = snd =>
            {

                Action iloop = null;

                var r = new IHTMLInput();
                var label = new IHTMLLabel(snd.src, r).AttachToDocument();

                dynamic rr = r;

                rr.type = "range";

                r.AttachToDocument();

                Action newvolume = delegate
                {

                    snd.volume = int.Parse(r.value) / 100;
                };
                r.onchange +=
                    delegate
                    {
                        newvolume();
                    };

                iloop =
                    delegate
                    {
                        Console.WriteLine("at canplaythrough " + new { snd.duration });


                        newvolume();
                        snd.play();


                        snd.onended +=
                            delegate
                            {
                                Console.WriteLine("at onended");

                            };

                        //var xsnd = snd;

                        var xsnd = new IHTMLAudio { src = snd.src };
                        xsnd.autobuffer = true;

                        new ScriptCoreLib.JavaScript.Runtime.Timer(
                            delegate
                            {
                                snd.volume = snd.volume * 0.5;

                                Console.WriteLine("at timer " + new { snd.currentTime, snd.duration });
                                snd = xsnd;
                                iloop();
                            }
                        ).StartTimeout((int)(1000 * snd.duration - 0.8));


                        xsnd.load();
                    };

                snd.autobuffer = true;

                // http://areweplayingyet.org/event-canplaythrough
                Console.WriteLine("waiting for canplaythrough");

                snd.addEventListener(
                      "canplaythrough",
                      new Action(
                          delegate
                          {

                              iloop();
                          }
                      )
                );

                new IHTMLBreak().AttachToDocument();

                return
                    nextvolume =>
                    {


                        r.value = "" + (int)(nextvolume * 100);

                        newvolume();
                    };
            };


            //loop(new helicopter1wav());
            var r0 = loop(new dieselloop());

            var r1 = loop(new dieselloopm5());

            var r2 = loop(new dieselloopm5m5());

            // we need SIN



            var zero = 0;

            var lookup = new[] {
                new double [] {zero, 0, 0},             
                new double [] {0, 0, 1},             
                new double [] {0, 1, 0},             
                new double [] {1, 0, 0},             
            };

            var tween_r0 = NumericEmitter.OfDouble(
                (x, y) =>
                {
                    r0(x);
                }
            );


            var tween_r1 = NumericEmitter.OfDouble(
                (x, y) =>
                {
                    r1(x);
                }
            );

            var tween_r2 = NumericEmitter.OfDouble(
                  (x, y) =>
                  {
                      r2(x);
                  }
              );


            Action masterswitchchanged = delegate
            {
                var masterswitch = int.Parse(page.masterswitch.value);

                Console.WriteLine(
                    new { masterswitch }
                );

                lookup[masterswitch].With(
                    x =>
                    {
                        tween_r0(x[0], 0);
                        tween_r1(x[1], 0);
                        tween_r2(x[2], 0);
                    }
                );
            };
            page.masterswitch.onchange +=
                delegate
                {
                    masterswitchchanged();
                };

            page.masterswitch.value = "" + (lookup.Length - 1);

            masterswitchchanged();
        }
        //Revision: 3636
        //Author: zproxy
        //Date: 22. aprill 2012. a. 11:16:53
        //Message:

        //----
        //Added : /examples/java/OutRun4KTemplate
        //Added : /examples/java/OutRun4KTemplate/OutRun4KTemplate




        // http://www.digitalinsane.com/archives/2007/01/21/space_invaders/
        public SpaceInvaders()
        {

            ImageResources gfx = "http://server/";

            var overlay = new Overlay();

            overlay.BackgroundColor = Color.Black;
            overlay.MaximumOpacity = 1;
            overlay.ControlInBack.style.zIndex = 100000;
            overlay.ControlInFront.style.zIndex = 100001;


            var view = overlay.ControlInFront;

            view.style.textAlign = IStyle.TextAlignEnum.center;
            view.style.SetSize(480, 480);
            view.style.backgroundColor = Color.Green;
            view.style.color = Color.White;
            view.style.fontFamily = IStyle.FontFamilyEnum.Fixedsys;




            //Native.Document.body.appendChild(
            //    new IHTMLElement(IHTMLElement.HTMLElementEnum.center,
            //    view)
            //    );



            //Native.Document.body.style.backgroundColor = Color.Black;
            // Native.Document.body.style.overflow = IStyle.OverflowEnum.hidden;

            System.Func<IHTMLDiv> CreateCanvas =
                delegate
                {
                    var c = new IHTMLDiv();

                    c.style.overflow = IStyle.OverflowEnum.hidden;
                    c.style.SetLocation(1, 1, 478, 478);

                    return c;
                };

            view.style.position = IStyle.PositionEnum.relative;

            var canvas = CreateCanvas();
            var menu = CreateCanvas();

            canvas.style.backgroundColor = Color.Black;


            view.appendChild(canvas, menu);

            var msg_loading = new IHTMLDiv("loading...");

            msg_loading.style.color = Color.Green;

            menu.appendChild(msg_loading);

            // at this point we want our images

            overlay.Visible = true;

            ScriptCoreLib.JavaScript.Runtime.Timer.DoAsync(overlay.UpdateLocation);

            // now wait while all images are loaded/complete

            ((fbool)(() => !gfx.IsComplete)).Trigger(
            delegate
            {
                // loading images is done now.



                // build the scoreboard
                var MyEnemyDirectory = new EnemyDirectory(gfx);

                var board = new ScoreBoard(gfx);

                board.Control.style.SetLocation(8, 8, 464, 64);

                canvas.appendChild(board.Control);

                board.Lives = 2;
                board.Score = 450;

                // now we can see lives and score.
                // ie does not issue keypress for control keys.
                // scriptcorelib should filter firefox events...

                // lets show main menu

                var mmenu = new MainMenu(MyEnemyDirectory, gfx);
                var gameovermenu = new GameOverMenu();

                menu.appendChild(mmenu.Control, gameovermenu.Control);

                gameovermenu.Visible = false;
                gameovermenu.Control.style.SetLocation(0, 100, 468, 468 - 100);

                mmenu.Control.style.SetLocation(0, 64, 468, 468 - 64);
                mmenu.Visible = true;

                var Enemy_Ammo = new AmmoInfo
                                 {
                                     Color = Color.White,
                                     Speed = 8
                                 };

                var Player = (IHTMLImage)gfx.biggun.Clone();
                var Player_Ammo = new AmmoInfo
                                  {
                                      Color = Color.Green,
                                      Speed = -8
                                  };

                var Map_Top = 64;
                var Map_Left = 20;
                var Map_Right = 450;
                var Map_Bottom = 470;

                var Map_Rect = new Rectangle();

                Map_Rect.Top = Map_Top;
                Map_Rect.Left = Map_Left;
                Map_Rect.Right = Map_Right;
                Map_Rect.Bottom = Map_Bottom;

                var Player_Y = 460;
                var Player_X = 200;

                var Player_X_step = 8;

                Action<int> UpdatePlayer =
                    delegate(int v)
                    {
                        Player_X += v;

                        if (Player_X < Map_Left)
                            Player_X = Map_Left;

                        if (Player_X > Map_Right)
                            Player_X = Map_Right;


                        Player.SetCenteredLocation(Player_X, Player_Y);
                        Player.style.position = IStyle.PositionEnum.absolute;
                    };

                Player.Hide();

                canvas.appendChild(Player, Player_Ammo.Control, Enemy_Ammo.Control);

                AmmoInfo[] KnownAmmo = new[] { Player_Ammo, Enemy_Ammo };

                var KnownConcrete = new List<Concrete>();
                var ConcreteTop = 432;

                KnownConcrete.AddRange(Concrete.BuildAt(new Point(62 + 120 * 0, ConcreteTop)));
                KnownConcrete.AddRange(Concrete.BuildAt(new Point(62 + 120 * 1, ConcreteTop)));
                KnownConcrete.AddRange(Concrete.BuildAt(new Point(62 + 120 * 2, ConcreteTop)));
                KnownConcrete.AddRange(Concrete.BuildAt(new Point(62 + 120 * 3, ConcreteTop)));

                foreach (Concrete v in KnownConcrete.ToArray())
                {
                    canvas.appendChild(v.Control);
                }


                var UFO = new EnemyUnit(MyEnemyDirectory.UFO);
                var UFO_Direction = 1;

                UFO.Visible = false;

                canvas.appendChild(UFO.Control);


                var EnemyTop = 128;
                var EnemySpacing = 32;
                var EnemyCount = 9;

                var KnownEnemies = new List<EnemyUnit>();

                KnownEnemies.AddRange(EnemyUnit.Build(MyEnemyDirectory.A, 20, EnemyTop + 0 * EnemySpacing, EnemyCount, EnemySpacing));
                KnownEnemies.AddRange(EnemyUnit.Build(MyEnemyDirectory.B, 20, EnemyTop + 1 * EnemySpacing, EnemyCount, EnemySpacing));
                KnownEnemies.AddRange(EnemyUnit.Build(MyEnemyDirectory.B, 20, EnemyTop + 2 * EnemySpacing, EnemyCount, EnemySpacing));
                KnownEnemies.AddRange(EnemyUnit.Build(MyEnemyDirectory.C, 20, EnemyTop + 3 * EnemySpacing, EnemyCount, EnemySpacing));
                KnownEnemies.AddRange(EnemyUnit.Build(MyEnemyDirectory.C, 20, EnemyTop + 4 * EnemySpacing, EnemyCount, EnemySpacing));

                foreach (EnemyUnit v in KnownEnemies.ToArray())
                {
                    canvas.appendChild(v.Control);
                }

                var HitDamage = 40;

                var GameTimer = new ScriptCoreLib.JavaScript.Runtime.Timer();

                int GangDirection = 1;

                Action<string> EndGame =
                    delegate
                    {
                        gameovermenu.Visible = true;

                        GameTimer.Stop();
                    };

                #region DoAmmoDamage
                Func<AmmoInfo, bool> DoAmmoDamage =
                    delegate(AmmoInfo a)
                    {
                        bool hit = false;

                        #region did we hit ufo?
                        if (UFO.Visible)
                        {
                            if (UFO.Bounds.Contains(a.Location))
                            {
                                board.Score += UFO.Info.Points;

                                UFO.Visible = false;

                                hit = true;
                            }
                        }
                        #endregion

                        #region did we hit player
                        if (Player.Bounds.Contains(a.Location))
                        {
                            board.Lives--;

                            hit = true;

                            if (board.Lives < 1)
                            {
                                EndGame("Ship destroied");

                            }
                        }
                        #endregion


                        foreach (Concrete v in KnownConcrete.ToArray())
                        {
                            if (v.Visible)
                            {
                                if (v.Bounds.Contains(a.Location))
                                {
                                    v.Health -= HitDamage;

                                    if (v.Health > 0)
                                    {
                                        hit = true;
                                    }
                                    else
                                    {
                                        v.Visible = false;
                                    }
                                }
                            }
                        }

                        foreach (EnemyUnit v in KnownEnemies.ToArray())
                        {
                            if (v.Visible)
                            {
                                if (v.Bounds.Contains(a.Location))
                                {
                                    v.Visible = false;

                                    hit = true;
                                    new SpaceInvadersTemplate.HTML.Audio.FromAssets.invaderexplode().play();

                                    board.Score += v.Info.Points;
                                }
                            }
                        }



                        return hit;
                    };
                #endregion


                var MyRandom = new System.Random();

                var mothershiploop = new SpaceInvadersTemplate.HTML.Audio.FromAssets.mothershiploopx
                {

                    loop = true
                };


                var duh = new IHTMLAudio[] { 
                    new SpaceInvadersTemplate.HTML.Audio.FromAssets.duh0(),
                    new SpaceInvadersTemplate.HTML.Audio.FromAssets.duh1(),
                    new SpaceInvadersTemplate.HTML.Audio.FromAssets.duh2(),
                    new SpaceInvadersTemplate.HTML.Audio.FromAssets.duh3(),
                };

                var duh_cycle = duh.ToCyclicAction(a => a.play());


                #region EnemyAction
                Action EnemyAction =
                    delegate
                    {
                        #region create ufo

                        if (!UFO.Visible)
                        {
                            if (MyRandom.NextDouble() < 0.1)
                            {
                                Console.WriteLine("UFO!");
                                mothershiploop.play();

                                if (MyRandom.NextDouble() > 0.5)
                                {
                                    UFO_Direction = 1;
                                    UFO.MoveTo(0, EnemyTop - UFO.Control.height * 2);
                                }
                                else
                                {
                                    UFO_Direction = -1;
                                    UFO.MoveTo(478, EnemyTop - UFO.Control.height * 2);
                                }

                                UFO.Visible = true;
                            }
                        }
                        #endregion

                        var ev = Enumerable.Where(KnownEnemies.ToArray(), i => i.Visible);

                        if (!Enemy_Ammo.Visible)
                        {
                            var ei = (int)System.Math.Round(MyRandom.NextDouble() * Enumerable.Count(ev));

                            EnemyUnit et = Enumerable.ElementAt(ev, ei);

                            if (et == null)
                                System.Console.WriteLine("element at " + ei + " not found");
                            else
                            {
                                int ey = Enumerable.Max(
                                    from i in ev where i.X == et.X select i.Y
                                    //    Enumerable.Select(Enumerable.Where(ev, i => i.X == et.X), i => i.Y)
                                );

                                Enemy_Ammo.MoveTo(et.X, ey + 20);
                                Enemy_Ammo.Visible = true;
                            }
                        }


                        #region MoveAll
                        Action<Point> MoveAll =
                            delegate(Point to)
                            {
                                var ConcreteReached = false;

                                foreach (EnemyUnit v in ev)
                                {
                                    var vy = v.Y + to.Y;

                                    if (vy > ConcreteTop)
                                    {
                                        ConcreteReached = true;
                                    }

                                    v.MoveTo(v.X + to.X, vy);
                                }

                                if (ConcreteReached)
                                {
                                    EndGame("The walls have been breached.");
                                }
                            };
                        #endregion

                        Action MoveAllDown =
                            delegate
                            {
                                MoveAll(new Point(0, 8));
                            };

                        duh_cycle();

                        #region move the gang
                        if (GangDirection > 0)
                        {
                            int ex_max = Enumerable.Max(Enumerable.Select(ev, i => i.X));

                            // gang goes right

                            if (ex_max >= Map_Rect.Right)
                            {
                                GangDirection = -1;
                                MoveAllDown();
                            }
                            else
                            {
                                MoveAll(new Point(4, 0));
                            }
                        }
                        else
                        {
                            int ex_min = Enumerable.Min(Enumerable.Select(ev, i => i.X));

                            // gang goes left

                            if (ex_min <= Map_Rect.Left)
                            {
                                GangDirection = 1;
                                MoveAllDown();
                            }
                            else
                            {
                                MoveAll(new Point(-4, 0));
                            }
                        }
                        #endregion

                    };
                #endregion

                bool GamePaused = false;




                GameTimer.Tick +=
                    delegate
                    {

                        #region only blink while paused
                        if (GamePaused)
                        {
                            if (GameTimer.Counter % 15 == 0)
                            {
                                Player.ToggleVisible();
                            }

                            return;
                        }
                        #endregion



                        Player.Show();

                        #region move ufo

                        if (UFO.Visible)
                        {
                            if (UFO_Direction > 0)
                            {
                                UFO.MoveTo(UFO.X + 4, UFO.Y);

                                if (UFO.X > 478 + UFO.Control.width)
                                {
                                    UFO.Visible = false;
                                    mothershiploop.pause();
                                }
                            }
                            else
                            {
                                UFO.MoveTo(UFO.X - 4, UFO.Y);

                                if (UFO.X < -UFO.Control.width)
                                {
                                    UFO.Visible = false;
                                    mothershiploop.pause();
                                }
                            }
                        }
                        #endregion


                        #region do ammo stuff
                        foreach (AmmoInfo v in KnownAmmo)
                        {
                            if (v.Visible)
                            {
                                var y = v.Y + v.Speed;

                                if (Map_Rect.Contains(new Point(v.X, y)))
                                {
                                    // did we hit?
                                    if (DoAmmoDamage(v))
                                    {

                                        v.Visible = false;
                                    }
                                    else
                                    {
                                        v.MoveTo(v.X, y);
                                    }
                                }
                                else
                                {
                                    v.Visible = false;
                                }
                            }
                        }
                        #endregion



                        var AliveEnemies = Enumerable.Where(KnownEnemies.ToArray(), i => i.Visible);
                        var AliveCount = Enumerable.Count(AliveEnemies);

                        if (AliveCount == 0)
                        {
                            EndGame("Aliens destoried");

                            return;
                        }

                        if (GameTimer.Counter % (AliveCount / 2) == 0)
                        {
                            EnemyAction();
                        }

                    };


                #region ResetGame
                Action ResetGame =
                    delegate
                    {
                        mmenu.Visible = false;

                        Player_X = 220;
                        board.Score = 0;
                        board.Lives = 3;

                        Player.Show();

                        foreach (Concrete v in KnownConcrete.ToArray())
                        {
                            v.Health = 255;
                            v.Visible = true;
                        }


                        foreach (EnemyUnit v in KnownEnemies.ToArray())
                        {
                            v.ResetPosition();
                            v.Visible = true;
                        }

                        EnemyAction();

                        GameTimer.StartInterval(50);

                        UpdatePlayer(0);
                    };
                #endregion

                Action EgoShoot =
                    delegate
                    {
                        if (!Player_Ammo.Visible)
                        {
                            Player_Ammo.MoveTo(Player_X, Player_Y - 20);

                            new SpaceInvadersTemplate.HTML.Audio.FromAssets.firemissile().play();

                            Player_Ammo.Visible = true;

                        }
                    };

                overlay.ControlInBack.onclick +=
                    delegate
                    {
                        if (mmenu.Visible)
                            ResetGame();
                        else
                            EgoShoot();
                    };


                double gamma = 0;

                //Native.window.ondeviceorientation +=
                //    eventData =>
                //    {
                //        if (eventData.gamma < -50)
                //            gamma = eventData.beta;
                //        else
                //            gamma = eventData.gamma;


                //    };

                new ScriptCoreLib.JavaScript.Runtime.Timer(
                    t =>
                    {
                        // gamma is the left-to-right tilt in degrees, where right is positive
                        if (gamma < -15)
                        {
                            if (mmenu.Visible)
                                ResetGame();
                            else
                                UpdatePlayer(-Player_X_step);
                        }

                        if (gamma > 15)
                        {
                            if (mmenu.Visible)
                                ResetGame();
                            else
                                UpdatePlayer(Player_X_step);
                        }
                    }
                ).StartInterval(100);

                Native.Document.onkeydown += delegate(IEvent ev)
                {
                    Console.WriteLine(new { ev.KeyCode }.ToString());

                    if (mmenu.Visible)
                    {
                        if (ev.IsReturn)
                        {

                            ResetGame();

                        }

                        return;
                    }
                    else
                    {
                        if (ev.IsEscape)
                        {
                            GameTimer.Stop();

                            Player.Hide();

                            mmenu.Visible = true;

                            foreach (AmmoInfo v in KnownAmmo)
                            {
                                v.Visible = false;
                            }

                            foreach (Concrete v in KnownConcrete.ToArray())
                            {
                                v.Visible = false;
                            }

                            foreach (EnemyUnit v in KnownEnemies.ToArray())
                            {
                                v.Visible = false;
                            }

                            UFO.Visible = false;

                            gameovermenu.Visible = false;

                            // the animated gifs would stop after escape key
                            ev.preventDefault();

                            GamePaused = false;
                        }
                    }

                    int key_p = 80;


                    if (ev.KeyCode == key_p)
                    {
                        GamePaused = !GamePaused;
                    }

                    // player shouldn't really move while game is paused
                    // its cheating:)
                    if (GamePaused)
                        return;

                    int key_right = 39;
                    int key_left = 37;

                    if (ev.KeyCode == key_left)
                    {
                        UpdatePlayer(-Player_X_step);
                    }
                    else if (ev.KeyCode == key_right)
                    {
                        UpdatePlayer(Player_X_step);
                    }
                    else if (ev.IsSpaceOrEnterKey())
                    {
                        // the animated gifs would stop after escape key
                        ev.preventDefault();

                        EgoShoot();
                    }
                    else
                    {
                        Console.WriteLine(new { UnknownKeyCode = ev.KeyCode }.ToString());
                    }
                };

                msg_loading.Orphanize();
            }
            , 50);


        }
        /// <summary>
        /// This is a javascript application.
        /// </summary>
        /// <param name="page">HTML document rendered by the web server which can now be enhanced.</param>
        public OtherApplication(IOtherPage page)
        {
            var AudioLinks = this.AudioLinks.ToArray();

            Native.Document.body.Clear();

            new IHTMLButton { innerText = "open Default page" }.AttachToDocument().With(
                btn =>
                {
                    new HTML.Images.FromAssets.jsc().AttachTo(btn);

                    btn.onclick +=
                       delegate
                       {
                           new IHTMLIFrame
                           {
                               src = "/"
                           }.AttachToDocument();

                           //Native.Window.open("/", "_self");

                       };
                }
            );

            AudioLinks.WithEach(
                a =>
                {
                    IHTMLAudio audio = null;

                    new IHTMLButton { innerText = a.innerText }.AttachToDocument().With(
                        btn =>
                        {
                            btn.style.display = IStyle.DisplayEnum.block;

                            btn.onclick +=
                                delegate
                                {
                                    if (audio == null)
                                    {
                                        audio = new IHTMLAudio { src = a.href }.AttachToDocument();
                                        audio.play();
                                    }
                                    else
                                    {
                                        if (audio.paused)
                                            audio.play();
                                        else
                                            audio.pause();
                                    }
                                };
                        }
                    );

                }
            );


            // XMLHttpRequest cannot load http://192.168.1.100:16304/xml?WebMethod=06000001. Origin http://www.webgljobs.com is not allowed by Access-Control-Allow-Origin.
            // Send data from JavaScript to the server tier
            //service.WebMethod2(
            //    @"other",
            //    value => value.ToDocumentTitle()
            //);
        }