/// <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)
        {
            var l = new NotificationLayout().layout;

            l.AttachToDocument();

            var div0 = new IHTMLDiv().AttachToDocument();

            new { }.With(
                async delegate
                {

                    do
                    {
                        div0.Clear();

                        new IHTMLHorizontalRule().AttachToDocument();

                        Task<ISVGSVGElement> n = l;

                        var svg = await n;

                        IHTMLImage i = svg;

                        var c = new CanvasRenderingContext2D(l.clientWidth, l.clientHeight);
                        c.drawImage(i, 0, 0, l.clientWidth, l.clientHeight);
                        c.canvas.AttachTo(div0);
                    }
                    while (await l.async.onmutation);

                }
            );
        }
        public static void RefreshComments(this IBacicInterface intFace, IHTMLDiv commentDiv)
        {
            commentDiv.Clear();

            Action refresh = async delegate
            {
                var comments = await intFace.GetAllViewComments(Native.document.location.hash);
                if (comments != null)
                {
                    for (var r = 0; r < comments.Rows.Count; r++)
                    {
                        var row = (global::Abstractatech.Comments.Schema.CommentCommentTableRow)comments.Rows[r];
                        var container = new CommentRow();
                        container.name.innerText = row.Name;
                        container.email.innerText = row.Email;
                        container.time.innerText = row.Timestamp.ToString("dd.MM.yyyy HH:mm:ss");
                        container.content.style.whiteSpace = IStyle.WhiteSpaceEnum.pre;
                        container.content.innerText = row.Comment;

                        container.AttachTo(commentDiv);
                    }
                }
            };
            refresh();
        }
		public Application(IAbout a)
		{
			var s = new InternalSaveActionSprite();

			s.AttachSpriteTo(a.Content);

			s.WebService = new ApplicationWebService();

			var pp = new ProjectNameInput();

			pp.AttachControlTo(a.Content);

			var Files = new IHTMLDiv().AttachTo(a.Content);

			s.WhenReady(
				i =>
				{
					Action Update = delegate
					{
						var sln = new SolutionBuilder
						{
							Name = pp.ProjectName.Text
						};

						i.FileName = sln.Name + ".zip";
						i.Clear();

						Files.Clear();

						sln.WriteTo(
							(SolutionFile f) =>
							{
								new IHTMLPre { innerText = f.Name }.AttachTo(Files);

								i.Add(f.Name, f.Content);
							}
						);
					};

					pp.UpdateButton.TextChanged +=
						delegate
						{
						};

					pp.UpdateButton.Click +=
						delegate
						{
							Update();
						};

					Update();
				}
			);
		}
        //public readonly ApplicationWebService service = new ApplicationWebService();

        /// <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(IDefault page)
        {
            var service = this;

            #region pre
            Func<string, IHTMLDiv, IHTMLElement> pre =
                (value, output) =>
                {
                    return new IHTMLPre { innerText = value }.AttachTo(output);
                };
            #endregion

            #region pre
            Func<string, IHTMLDiv, IHTMLElement> browse = null;

            browse =
                (path, output) =>
                {

                    var list = new IHTMLButton { innerText = path }.AttachTo(output);


                    var group = new IHTMLDiv().AttachTo(output);




                    list.onclick +=
                        delegate
                        {
                            group.style.margin = "1em";
                            group.style.paddingLeft = "1em";
                            group.style.border = "1px solid gray";

                            list.disabled = true;

                            service.File_list(path,
                                ydirectory: value =>
                                {
                                    browse(path + "/" + value, group);
                                },

                                yfile: value =>
                                {
                                    var link = new IHTMLAnchor { href = "/io" + path + "/" + value, innerText = value };

                                    link.style.display = IStyle.DisplayEnum.block;
                                    link.AttachTo(group);
                                }
                            );
                        };

                    return group;
                };
            #endregion



            #region f
            Action<string, string, Action<string, Action<string>>, Func<string, IHTMLDiv, IHTMLElement>> f =
                (text, arg1, c, y) =>
                {
                    var btn = new IHTMLButton(text).AttachToDocument();
                    var output = new IHTMLDiv().AttachToDocument();

                    btn.onclick +=
                        e =>
                        {
                            btn.style.color = JSColor.Red;

                            output.Clear();

                            c(arg1,
                                value =>
                                {
                                    btn.style.color = JSColor.Blue;


                                    y(value, output);
                                }
                            );
                        }
                    ;
                };
            #endregion

            #region ff
            Action<string, Func<Task<string>>, Func<string, IHTMLDiv, IHTMLElement>> ff =
                (text, c, y) =>
                {
                    var btn = new IHTMLButton(text).AttachToDocument();
                    var output = new IHTMLDiv().AttachToDocument();

                    btn.WhenClicked(
                        async e =>
                        {
                            btn.style.color = JSColor.Red;

                            output.Clear();

                            var value = await c();

                            btn.style.color = JSColor.Blue;


                            y(value, output);
                        }
                     );
                };
            #endregion


#if CORE_PARTIAL
            ff("Environment_getDataDirectory", () => service.Environment_getDataDirectory(), browse);
            ff("Environment_getDownloadCacheDirectory", () => service.Environment_getDownloadCacheDirectory(), browse);
            ff("Environment_getExternalStorageDirectory", () => service.Environment_getExternalStorageDirectory(), browse);
            ff("Environment_getExternalStorageState", () => service.Environment_getExternalStorageState(), pre);
            ff("Environment_getRootDirectory", () => service.Environment_getRootDirectory(), browse);

            //service.Environment_DIRECTORY("",
            //    (
            //        string DIRECTORY_MUSIC,
            //        string DIRECTORY_PODCASTS,
            //        string DIRECTORY_RINGTONES,
            //        string DIRECTORY_ALARMS,
            //        string DIRECTORY_NOTIFICATIONS,
            //        string DIRECTORY_PICTURES,
            //        string DIRECTORY_MOVIES,
            //        string DIRECTORY_DOWNLOADS,
            //        string DIRECTORY_DCIM
            //    ) =>

            f("Environment_getExternalStoragePublicDirectory DIRECTORY_MUSIC", DIRECTORY_MUSIC, service.Environment_getExternalStoragePublicDirectory, browse);
            f("Environment_getExternalStoragePublicDirectory DIRECTORY_PODCASTS", DIRECTORY_PODCASTS, service.Environment_getExternalStoragePublicDirectory, browse);
            f("Environment_getExternalStoragePublicDirectory DIRECTORY_RINGTONES", DIRECTORY_RINGTONES, service.Environment_getExternalStoragePublicDirectory, browse);
            f("Environment_getExternalStoragePublicDirectory DIRECTORY_ALARMS", DIRECTORY_ALARMS, service.Environment_getExternalStoragePublicDirectory, browse);
            f("Environment_getExternalStoragePublicDirectory DIRECTORY_NOTIFICATIONS", DIRECTORY_NOTIFICATIONS, service.Environment_getExternalStoragePublicDirectory, browse);
            f("Environment_getExternalStoragePublicDirectory DIRECTORY_PICTURES", DIRECTORY_PICTURES, service.Environment_getExternalStoragePublicDirectory, browse);
            f("Environment_getExternalStoragePublicDirectory DIRECTORY_MOVIES", DIRECTORY_MOVIES, service.Environment_getExternalStoragePublicDirectory, browse);
            f("Environment_getExternalStoragePublicDirectory DIRECTORY_DOWNLOADS", DIRECTORY_DOWNLOADS, service.Environment_getExternalStoragePublicDirectory, browse);

#endif

            f("Environment_getExternalStoragePublicDirectory DIRECTORY_DCIM", DIRECTORY_DCIM, service.Environment_getExternalStoragePublicDirectory, browse);



            new IHTMLElement(IHTMLElement.HTMLElementEnum.hr).AttachToDocument();



            // new IHTMLButton("Environment_getDownloadCacheDirectory").AttachToDocument().onclick +=
            //    e => service.Environment_getDownloadCacheDirectory("",
            //            value => new IHTMLPre { innerText = value }.AttachToDocument()
            //);
        }
        // 20140526 roslyn friendly!
        // and broken again

        //        script: error JSC1000:
        //error:
        //  statement cannot be a load instruction(or is it a bug?)
        //  [0x000a]
        //        ldarg.0    +1 -0

        // assembly: V:\Abstractatech.JavaScript.Avatar.Application.exe
        // type: Abstractatech.JavaScript.Avatar.ApplicationImplementation+<MakeCamGrabber>d__1+<MoveNext>0600002d, Abstractatech.JavaScript.Avatar.Application, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
        // offset: 0x000a
        //  method:Int32<06ad> call.try(<MoveNext>0600002d, <MakeCamGrabber>d__1 ByRef, System.Runtime.CompilerServices.TaskAwaiter`1[ScriptCoreLib.JavaScript.DOM.HTML.IHTMLImage] ByRef, System.Runtime.CompilerServic

        public static async void MakeCamGrabber(
            IHTMLDiv c,
            bool sizeToWindow = false,
            Action<WebCamAvatarsSheet1Row> yield = null
            )
        {
            if (sizeToWindow)
            {
                #region onresize
                Native.window.With(
                    async window =>
                    {
                        while (true)
                        {
                            c.style.transformOrigin = "0% 0%";

                            var scale =

                                Native.window.Height / (double)(480 + 96);

                            if (Native.window.Height > Native.window.Width)
                                scale = Native.window.Width / (double)(640);


                            c.style.transform = "scale("
                                + scale
                                + ")";

                            var w = (int)(scale * (640));
                            var h = (int)(scale * (480 + 96));


                            c.style.width = w + "px";
                            c.style.height = h + "px";

                            c.style.SetLocation(
                                (Native.window.Width - w) / 2,
                                (Native.window.Height - h) / 2
                            );

                            await window.async.onresize;
                        }
                    }
                );
                #endregion

            }

            c.style.backgroundColor = "black";

            #region localStorageKeys

            // or webSQL?
            var localStorageKeys = new
            {

                img640x480 = new { img = "avatar", w = 640, h = 480 },
                img96gif = new { img = "avatar", w = 96, h = 96 },

                frames = new[] {
                            new { index= 0, img = "avatar", w = 96, h = 96 },
                            new { index= 1, img = "avatar", w = 96, h = 96 },
                            new { index= 2, img = "avatar", w = 96, h = 96 },
                            new { index= 3, img = "avatar", w = 96, h = 96 },
                        }
            };
            #endregion



            //c.css.children
            c.css.children.style.SetLocation(0, 0);

            c.style.position = IStyle.PositionEnum.relative;
            c.style.width = (640) + "px";
            c.style.height = (480 + 96) + "px";






            c.css.hover.style.cursor = IStyle.CursorEnum.pointer;

            #region empty
            var css = c.css.empty.before;

            css.style.textAlign = IStyle.TextAlignEnum.center;
            css.style.display = IStyle.DisplayEnum.block;
            css.style.width = (640) + "px";
            css.style.color = "white";
            css.style.paddingTop = 300 + "px";


            c.css.hover.empty.before.style.color = "yellow";
            #endregion




            var retry = 0;
            retry:
            retry++;

            Console.WriteLine(new { retry });


            css.contentText = "either drag a picture here -or- click here to use your webcam";

            var snapshot = new CanvasRenderingContext2D(640, 480);

            var frames = new List<IHTMLImage>();

            c.css[IHTMLElement.HTMLElementEnum.img][0].style.SetLocation(96 * 0, 480);
            c.css[IHTMLElement.HTMLElementEnum.img][1].style.SetLocation(96 * 1, 480);
            c.css[IHTMLElement.HTMLElementEnum.img][2].style.SetLocation(96 * 2, 480);
            c.css[IHTMLElement.HTMLElementEnum.img][3].style.SetLocation(96 * 3, 480);
            c.css[IHTMLElement.HTMLElementEnum.img][4].style.SetLocation(96 * 4, 480);
            c.css[IHTMLElement.HTMLElementEnum.img][5].style.SetLocation(96 * 5, 480);

            var size = 400;

            #region newmask
            Action newmask = delegate
            {
                #region grid
                new IHTMLDiv
                {

                }.AttachTo(c).With(
                    async grid =>
                    {
                        grid.style.SetLocation(
                            (640 - size) / 2,
                            (480 - size) / 2,

                            size - 2,
                            size - 2
                        );

                        var s = Stopwatch.StartNew();

                        // X:\jsc.svn\examples\javascript\LINQ\LINQWebCamAvatars\LINQWebCamAvatars\Application.cs
                        // until orphanized
                        while (c.parentNode != null)
                        {
                            //await Native.window.requestAnimationFrameAsync;
                            await Native.window.async.onframe;

                            var a = (Math.Cos(s.ElapsedMilliseconds * 0.001) + 1) / 2.0;

                            grid.style.border = "1px dotted rgba(255,255,255, "
                                + (1.0 - a)
                                + ")";

                            //mask_css.style.Opacity = a;

                        }
                    }
                );
                #endregion

                #region mask
                var mask = new CanvasRenderingContext2D(640, 480 + 96);

                mask.canvas.style.zIndex = 100;

                //mask.drawImage(
                //    v, 0, 0,

                //    mask.canvas.width,
                //    mask.canvas.height
                //);

                mask.fillStyle = "rgba(0,0,0, 0.8)";
                mask.fillRect(
                       0, 0,

                       640,
                       480 + 96
                   );


                mask.clearRect(
                      (640 - size) / 2,
                        (480 - size) / 2,

                        size,
                        size
                );



                //var bytes = i.bytes;

                mask.canvas.AttachTo(c);
                #endregion


            };
            #endregion


            #region localStorage
            var base64 = Native.window.localStorage[localStorageKeys.img640x480];
            if (base64 != null)
            {
                var base64image = new IHTMLImage { src = base64 };

                await base64image;

                snapshot.drawImage(base64image, 0, 0, 640, 480);
                snapshot.canvas.AttachTo(c);


                for (int i = 0; i < 5; i++)
                {
                    var base64f = Native.window.localStorage[localStorageKeys.frames[
                        localStorageKeys.frames.Length - i - 1]];

                    if (base64f != null)
                    {
                        var newframe = new IHTMLImage { src = base64f };
                        newframe.AttachTo(c);
                        frames.Add(newframe);
                    }
                }



                newmask();

                var base64gif = Native.window.localStorage[localStorageKeys.img96gif];

                #region atgif
                Action<string> atgif =
                    gif =>
                    {
                        //Native.document.title = new { gif.Length }.ToString();

                        var newframe = new IHTMLImage { src = gif };

                        newframe.style.zIndex = 300;

                        newframe.AttachTo(c);
                        frames.Add(newframe);

                        //if (frames.Count > 5)
                        //    frames.Remove(frames[0].Orphanize());
                    };
                #endregion


                if (base64gif != null)
                    atgif(base64gif);
                else
                {
                    var bytes = frames.Select(x => x.bytes.Result).ToArray().AsEnumerable();

                    //bytes = bytes.Concat(bytes.Skip(1).Reverse().Skip(1)).ToArray().AsEnumerable();

                    // build it
                    new GIFEncoderWorker(
                         96,
                         96,
                             delay: 1000 / 10,
                         frames: bytes,
                         AtFrame:
                          async index =>
                          {
                              //Native.document.title = new { index }.ToString();
                          }


                     ).Task.ContinueWithResult(
                        gif =>
                        {
                            Native.window.localStorage[localStorageKeys.img96gif] = gif;


                            // report sizes. smaller is better if db
                            Console.WriteLine(
                                // { Avatar640x480 = 54843, Avatar96gif = 54734 } 
                                new
                                {
                                    Avatar640x480 = base64.Length,
                                    Avatar96gif = gif.Length
                                }
                            );


                            if (yield != null)
                                yield(
                                    new WebCamAvatarsSheet1Row
                                    {
                                        Avatar640x480 = base64,
                                        Avatar96frame1 = Native.window.localStorage[localStorageKeys.frames[0]],
                                        // do we want to report frames?
                                        Avatar96gif = gif
                                    }
                                );


                            atgif(gif);
                        }
                        );
                }

            }
            #endregion

            Console.WriteLine("await c.async.onclick");
            await c.async.onclick;
            Console.WriteLine("await c.async.onclick done");

            c.Clear();

            css.content = "awaiting for video";




            var v = await Native.window.navigator.async.onvideo;


            v.AttachTo(c);
            v.play();


            var mask_css = c.css[IHTMLElement.HTMLElementEnum.canvas];



            newmask();

            var z96 = new CanvasRenderingContext2D(96, 96);

            z96.canvas.AttachTo(c);
            //z96.canvas.style.backgroundColor = "gray";
            z96.canvas.style.SetLocation(96 * 5, 480);

            z96.canvas.style.zIndex = 300;


            var ok = c.async.onclick;

            #region frames



            while (!ok.IsCompleted)
            {

                z96.drawImage(
                    image: v,
                    sx: (640 - size) / 2,
                    sy: (480 - size) / 2,

                    sw: size,
                    sh: size,
                    dx: 0,
                    dy: 0,
                    dw: 96,
                    dh: 96
                );

                var newframe = new IHTMLImage { src = z96.canvas.toDataURL() };
                newframe.AttachTo(c);
                frames.Add(newframe);

                if (frames.Count > 5)
                    frames.Remove(frames[0].Orphanize());


                await (1000 / 15);
            }
            #endregion

            snapshot.drawImage(v, 0, 0, 640, 480);

            #region localStorage

            // https://developer.mozilla.org/en/docs/Web/API/HTMLCanvasElement
            //Native.window.localStorage[localStorageKeys.img640x480] = 

            var firstTry = snapshot.canvas.toDataURL(

            // shall we use enum
            type: "image/jpeg"
            );
            if (firstTry.Length >= (1024 * 64))
            {
                Console.WriteLine("Reducing quality");
                firstTry = snapshot.canvas.toDataURL(

            // shall we use enum
            type: "image/jpeg",
            quality: 0.5
            );
            }

            // can we use SQL instead now?
            Native.window.localStorage[localStorageKeys.img640x480] = firstTry;



            frames.WithEachIndex(
                (k, index) =>
                {
                    Native.window.localStorage[localStorageKeys.frames[index]] = k.src;
                }
            );

            Native.window.localStorage.removeItem(localStorageKeys.img96gif);
            #endregion


            v.src = "";
            c.Clear();



            goto retry;
        }
        /// <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)
        {
            #region += Launched chrome.app.window
            dynamic self = Native.self;
            dynamic self_chrome = self.chrome;
            object self_chrome_socket = self_chrome.socket;

            if (self_chrome_socket != null)
            {
                if (!(Native.window.opener == null && Native.window.parent == Native.window.self))
                {
                    Console.WriteLine("chrome.app.window.create, is that you?");

                    // pass thru
                }
                else
                {
                    // should jsc send a copresence udp message?
                    chrome.runtime.UpdateAvailable += delegate
                    {
                        new chrome.Notification(title: "UpdateAvailable");

                    };

                    chrome.app.runtime.Launched += async delegate
                    {
                        // 0:12094ms chrome.app.window.create {{ href = chrome-extension://aemlnmcokphbneegoefdckonejmknohh/_generated_background_page.html }}
                        Console.WriteLine("chrome.app.window.create " + new { Native.document.location.href });

                        new chrome.Notification(title: "Launched2");

                        var xappwindow = await chrome.app.window.create(
                               Native.document.location.pathname, options: null
                        );

                        //xappwindow.setAlwaysOnTop

                        xappwindow.show();

                        await xappwindow.contentWindow.async.onload;

                        Console.WriteLine("chrome.app.window loaded!");
                    };


                    return;
                }
            }
            #endregion

            // 
            // http://stackoverflow.com/questions/13076272/how-do-i-give-webkitgetusermedia-permission-in-a-chrome-extension-popup-window
            // https://sites.google.com/a/jsc-solutions.net/work/knowledge-base/15-dualvr/20150712
            new { }.With(
                async delegate
                {
                    Native.body.Clear();
                    Native.document.documentElement.style.overflow = IStyle.OverflowEnum.auto;

                    new IHTMLPre
                    {
                        "GearVR should send analog and digital signal to start parallax tracking only if near zero rotation."
                    }.AttachToDocument();

                    // would it be easy to do head tracking via webcam for VR?
                    // the app would run on android, yet
                    // two sattelites could spawn on two laptops to track the head.

                    // would we be able to thread hop between camera devices and android?

                    // http://shopap.lenovo.com/hk/en/laptops/lenovo/u-series/u330p/
                    // The U330p's integrated 720p HD webcam


                    // HD wont work for chrome app?
                    var v = await Native.window.navigator.async.onvideo;
                    v.AttachToDocument();

                    v.play();

                    new IHTMLButton { "stop" }.AttachToDocument().onclick += delegate
                    {
                        //v.src = null;
                        v.src = "";
                        //v.pause();
                        //v.stop();
                    };

                    var sw = Stopwatch.StartNew();

                    while (v.videoWidth == 0)
                        await Native.window.async.onframe;


                    const int zoomx = 2;
                    //const int zoomy = 4;

                    //var ow = v.videoWidth / zoomx;
                    var ow = 512;
                    //var oh = v.videoHeight / zoomy;
                    //var oh = 256;
                    //var oh = 96;
                    //var oh = 256;
                    var oh = 128;

                    // 40 with udp
                    //var oh = 0xA0;
                    //var oh = 0xb0;

                    // 58
                    //var oh = 196;
                    // 35
                    //var oh = 256;

                    var aloop = new IHTMLInput
                    {
                        title = "loop it",

                        type = ScriptCoreLib.Shared.HTMLInputTypeEnum.checkbox,
                        @checked = true
                    }.AttachToDocument();

                    var slider = new IHTMLInput
                    {
                        title = "stabilizer?",

                        type = ScriptCoreLib.Shared.HTMLInputTypeEnum.range,
                        //max = 255,
                        //max = 128,
                        max = 64,

                        // https://sites.google.com/a/jsc-solutions.net/work/knowledge-base/15-dualvr/20150712-1
                        valueAsNumber = 48
                    }.AttachToDocument();


                    var z = 0;
                    var x = 0;
                    var y = 0;

                    var frame0in = new CanvasRenderingContext2D(ow, oh);

                    Action frame0in_drawImage = delegate
                    {

                        var clip = v.videoHeight / 6;

                        // 6000 zoom out
                        // 8000 zoom in

                        // haha. this wont work.
                        //var zz = (2000 - (z - 6000).Min(2000)) / 2000f;
                        //clip = (int)(clip * zz);

                        frame0in.drawImage(v, 0, clip, v.videoWidth, v.videoHeight - clip * 2, 0, 0, ow, oh);
                    };

                    //frame0in.canvas.AttachToDocument();

                    //var frame0out = new CanvasRenderingContext2D(ow, oh);
                    ////frame0out.canvas.AttachToDocument();

                    //var frame1out = new CanvasRenderingContext2D(ow, oh);
                    ////frame1out.canvas.AttachToDocument();

                    //var frame2out = new CanvasRenderingContext2D(ow, oh);
                    //frame2out.canvas.AttachToDocument();


                    var frame3out = new CanvasRenderingContext2D(ow, oh);
                    frame3out.canvas.AttachToDocument();


                    var frame0sw = Stopwatch.StartNew();
                    var frameID = 0;
                    var frame0sw0 = Stopwatch.StartNew();

                    var fps3 = 0;

                    // avg per sec x3
                    var fps3avg = new byte[20 * 3];



                    var sent = new IHTMLPre
                    {
                    }.AttachToDocument();


                    // https://sites.google.com/a/jsc-solutions.net/work/knowledge-base/15-dualvr/20150701


                    // what about 255.255.255.255 ?
                    chrome.socket.getNetworkList().ContinueWithResult(async n =>
                    {
                        // which networks should we notify of our data?

                        //new IHTMLPre { new { n.Length } }.AttachToDocument();

                        foreach (var item in n)
                        {
                            // https://sites.google.com/a/jsc-solutions.net/work/knowledge-base/15-dualvr/20150704
                            // skip ipv6
                            if (item.address.Contains(":"))
                                continue;

                            #region send
                            new IHTMLButton { "send onframe " + item.address }.AttachToDocument().With(
                                async refresh =>
                                {
                                    refresh.style.color = "blue";

                                    refresh.style.display = IStyle.DisplayEnum.block;

                                    // experimental until ref count 33?
                                    await refresh.async.onmousedown;

                                    refresh.disabled = true;

                                    var port = new Random().Next(16000, 40000);

                                    //new IHTMLPre { "about to bind... " + new { port } }.AttachToDocument();

                                    // where is bind async?
                                    var socket = new UdpClient();
                                    socket.Client.Bind(

                                         //new IPEndPoint(IPAddress.Any, port: 40000)
                                         new IPEndPoint(IPAddress.Parse(item.address), port)
                                     );


                                    // this will eat too much memory?
                                    //div.ownerDocument.defaultView.onframe +=
                                    Native.window.onframe += e =>
                                     {
                                         //var px = (float)(__yscan64max_ix - v.videoWidth / 2) / (float)v.videoWidth;
                                         var px0 = (float)(x - ow / 2) / (float)ow;
                                         var py0 = (float)(y - oh / 2) / (float)oh;


                                         // 4000 zoom out
                                         // 7000 zoom in

                                         // haha. this wont work.
                                         //var pz = ((z - 4500) / 2000f).Max(0f).Min(1.5f);

                                         // in a dark room?
                                         var pz = ((z - 6000) / 1000f).Max(0f).Min(1.5f);

                                         // allow py only if pz is negative.
                                         // 0 means py stays
                                         // 1 means py is zero

                                         var pzz = (1.0f - pz).Max(0.0f).Min(1.0f);

                                         var py = py0 * pzz;
                                         var px = px0 * pzz;

                                         pz -= 0.3f;
                                         // !! leaning in kills parallax left and up.
                                         // rotating on gear vr will cancel all parallax.

                                         // https://sites.google.com/a/jsc-solutions.net/work/knowledge-base/15-dualvr/20150704
                                         var nmessage = e.counter + ":" + px + ":" + py + ":" + pz;

                                         //sent.innerText = nmessage.Replace(":", ":\n") + new { py0, pzz, py };
                                         sent.innerText = nmessage.Replace(":", ":\n");

                                         var data = Encoding.UTF8.GetBytes(nmessage);      //creates a variable b of type byte



                                         //new IHTMLPre { "about to send... " + new { data.Length } }.AttachToDocument();

                                         // X:\jsc.svn\examples\javascript\chrome\apps\ChromeUDPNotification\ChromeUDPNotification\Application.cs
                                         socket.Send(
                                              data,
                                              data.Length,
                                              hostname: "239.1.2.3",
                                              port: 43834
                                          );
                                     };


                                }
                            );
                            #endregion

                        }
                    }
                );


                    var status = new IHTMLPre {
                        () => new {
                            frameID,
                            frame0sw.ElapsedMilliseconds,

                            fps = 1000 / frame0sw.ElapsedMilliseconds ,
                            fps3avg = (byte)fps3avg.Average(k => k),

                            x,y,z,

                            fps3,

                            // script: error JSC1000: No implementation found for this native method, please implement [System.String.Replace(System.Char, System.Char)]
                        }.ToString().Replace(",", ",\t")
                    }.AttachToDocument();


                    var fdiv = new IHTMLDiv { }.AttachToDocument();

                    new { }.With(
                        async delegate
                        {
                            var vw = ow;
                            var vh = oh;

                            #region 3 workers
                            // what about sending bytes[2,3] over?
                            byte[] rgba_bytes0in = null;
                            var rgba_bytes0in_set = new System.Threading.SemaphoreSlim(1);
                            byte[] rgba_bytes0out = null;
                            var rgba_bytes0out_set = new System.Threading.SemaphoreSlim(1);
                            //SemaphoreSlim rgba_bytes0out_set = new __SemaphoreSlim(1) { Name = "rgba_bytes0out_set" };


                            byte[] rgba_bytes1in = null;
                            var rgba_bytes1in_set = new System.Threading.SemaphoreSlim(1);
                            byte[] rgba_bytes1out = null;
                            var rgba_bytes1out_set = new System.Threading.SemaphoreSlim(1);

                            byte[] rgba_bytes2in = null;
                            var rgba_bytes2in_set = new System.Threading.SemaphoreSlim(1);
                            byte[] rgba_bytes2out = null;
                            var rgba_bytes2out_set = new System.Threading.SemaphoreSlim(1);


                            Task.Run(
                                async delegate
                                {
                                    var w = new WorkerThread(0, vw, vh);
                                    next:
                                    await rgba_bytes0in_set.WaitAsync();

                                    rgba_bytes0out = w.Invoke(rgba_bytes0in);
                                    rgba_bytes1out = null;
                                    rgba_bytes2out = null;

                                    rgba_bytes0in = null;
                                    rgba_bytes1in = null;
                                    rgba_bytes2in = null;
                                    // we should not sync back data we did not put there. nor should it be there anyway?
                                    rgba_bytes0out_set.Release();
                                    goto next;
                                }
                            );


                            Task.Run(
                                async delegate
                                {
                                    var w = new WorkerThread(1, vw, vh);
                                    next:
                                    await rgba_bytes1in_set.WaitAsync();
                                    rgba_bytes0out = null;
                                    rgba_bytes1out = w.Invoke(rgba_bytes1in);
                                    rgba_bytes2out = null;

                                    rgba_bytes0in = null;
                                    rgba_bytes1in = null;
                                    rgba_bytes2in = null;

                                    rgba_bytes1out_set.Release();
                                    goto next;
                                }
                            );


                            Task.Run(
                                async delegate
                                {
                                    var w = new WorkerThread(2, vw, vh);
                                    next:
                                    await rgba_bytes2in_set.WaitAsync();

                                    rgba_bytes0out = null;
                                    rgba_bytes1out = null;
                                    rgba_bytes2out = w.Invoke(rgba_bytes2in);
                                    rgba_bytes0in = null;
                                    rgba_bytes1in = null;
                                    rgba_bytes2in = null;


                                    rgba_bytes2out_set.Release();
                                    goto next;
                                }
                            );
                            #endregion

                            Console.WriteLine("worker0 spinning already...");

                            //do
                            await v.async.onclick;

                            {

                                frame0sw0 = Stopwatch.StartNew();
                                //Console.WriteLine(frame0sw0.ElapsedMilliseconds + " fetch frame0");

                                frame0in.drawImage(v, 0, v.videoHeight / 4, v.videoWidth, v.videoHeight / 2, 0, 0, vw, vh);
                                rgba_bytes0in = frame0in.bytes;
                                rgba_bytes0in_set.Release();
                                new IHTMLPre { frame0sw0.ElapsedMilliseconds + " frame0 posted" }.AttachTo(fdiv);

                                // await Task.Delay(1000 / 60);
                                // 300?
                                // Console.WriteLine(frame0sw0.ElapsedMilliseconds + " send frame2");
                                frame0in.drawImage(v, 0, v.videoHeight / 4, v.videoWidth, v.videoHeight / 2, 0, 0, vw, vh);
                                rgba_bytes1in = frame0in.bytes;
                                rgba_bytes1in_set.Release();
                                new IHTMLPre { frame0sw0.ElapsedMilliseconds + " frame1 posted" }.AttachTo(fdiv);

                                loop:
                                // 60fps!!
                                frameID += 3;

                                frame0in_drawImage();
                                rgba_bytes2in = frame0in.bytes;
                                rgba_bytes2in[0] = (byte)(frameID & 0xff);
                                rgba_bytes2in[1] = (byte)((frameID >> 8) & 0xff);
                                rgba_bytes2in[4] = slider;
                                rgba_bytes2in_set.Release();

                                //await Task.WhenAll(Native.window.async.onframe, rgba_bytes0out_set.WaitAsync());
                                await rgba_bytes0out_set.WaitAsync();
                                if (!aloop.@checked)
                                    new IHTMLPre { frame0sw0.ElapsedMilliseconds + " collected frame0" }.AttachTo(fdiv);
                                //frame0out.bytes = rgba_bytes0out;
                                //frame3out.drawImage(frame0out.canvas, 0, 0, vw, vh);
                                frame3out.bytes = rgba_bytes0out;
                                rgba_bytes2in = null;
                                rgba_bytes0out = null;

                                frame0in_drawImage();
                                rgba_bytes0in = frame0in.bytes;
                                rgba_bytes0in[0] = (byte)(frameID & 0xff);
                                rgba_bytes0in[1] = (byte)((frameID >> 8) & 0xff);
                                rgba_bytes0in[4] = slider;
                                rgba_bytes0in_set.Release();

                                //await Task.WhenAll(Native.window.async.onframe, rgba_bytes1out_set.WaitAsync());
                                await rgba_bytes1out_set.WaitAsync();
                                if (!aloop.@checked)
                                    new IHTMLPre { frame0sw0.ElapsedMilliseconds + " collected frame1" }.AttachTo(fdiv);
                                //frame1out.bytes = rgba_bytes1out;
                                //frame3out.drawImage(frame1out.canvas, 0, 0, vw, vh);
                                frame3out.bytes = rgba_bytes1out;
                                rgba_bytes0in = null;
                                rgba_bytes1out = null;


                                frame0in_drawImage();
                                rgba_bytes1in = frame0in.bytes;
                                rgba_bytes1in[0] = (byte)(frameID & 0xff);
                                rgba_bytes1in[1] = (byte)((frameID >> 8) & 0xff);
                                rgba_bytes1in[4] = slider;
                                rgba_bytes1in_set.Release();

                                await Task.WhenAll(Native.window.async.onframe, rgba_bytes2out_set.WaitAsync());
                                if (!aloop.@checked)
                                    new IHTMLPre { frame0sw0.ElapsedMilliseconds + " collected frame2, next? " + new { aloop.@checked } }.AttachTo(fdiv);

                                //
                                z = rgba_bytes2out[0] + (rgba_bytes2out[1] << 8);
                                x = rgba_bytes2out[4] + (rgba_bytes2out[5] << 8);
                                y = rgba_bytes2out[8];

                                //frame2out.bytes = rgba_bytes2out;
                                //frame3out.drawImage(frame2out.canvas, 0, 0, vw, vh);
                                frame3out.bytes = rgba_bytes2out;
                                rgba_bytes1in = null;
                                rgba_bytes2out = null;


                                frame0sw0.Stop();
                                frame0sw = frame0sw0;


                                //if (v.src == null)
                                //{
                                //    Native.body.style.backgroundColor = "red";
                                //    return;
                                //}

                                //if (aloop)
                                if (!aloop.@checked)
                                {
                                    //await Task.WhenAny(aloop.async.@checked, v.async.onclick);
                                    await v.async.onclick;

                                    fdiv.Clear();
                                }

                                frame0sw0 = Stopwatch.StartNew();
                                fps3 = (int)(3000 / frame0sw.ElapsedMilliseconds);
                                fps3avg[(frameID / 3) % fps3avg.Length] = (byte)fps3;

                                if (fps3 > 55)
                                {
                                    status.style.color = "blue";
                                }
                                else
                                {
                                    status.style.color = "red";
                                }

                                goto loop;


                                // 10000ms?
                                // 400ms?
                            }
                            //} while (await v.async.onclick);
                            //} while (await Native.window.async.onframe);
                        }
                    );

                    await Native.window.async.onblur;

                    Native.body.style.backgroundColor = "yellow";
                }
            );
        }
        public static async void MakeimageNotification(IHTMLDiv c, IAvatarNotificationInterface service)
        {
            WebCamAvatarsSheet1Row lastPicture = null;

            //new IStyle(page.ImgContainer.css + IHTMLElement.HTMLElementEnum.img)
            //{
            //    transition = "left linear 2000ms",
            //    position = IStyle.PositionEnum.absolute,
            //    Opacity = 1
            //};

            while (true)
            {
                var pic = await service.GetLastUserImage();

                if (lastPicture != null)
                {
                    if (pic != null)
                    {
                        Console.WriteLine(pic.Key.ToString());
                        Console.WriteLine(lastPicture.Key.ToString());
                        if (pic.Key == lastPicture.Key)
                        {
                            c.Clear();
                        }
                        else
                        {
                            IHTMLImage img = new IHTMLImage();
                            img.AttachTo(c);
                            img.src = pic.Avatar96frame1;
                            img.style.left = "-150px";
                            lastPicture = pic;

                            await 500;

                            Native.window.requestAnimationFrame += delegate
                            {
                                img.style.left = "50px";

                            };

                            await 10000;

                            Native.window.requestAnimationFrame += delegate
                            {
                                img.style.left = "-150px";

                            };
                        }
                    }
                    else
                    {
                        c.Clear();
                    }
                }
                else
                {
                    IHTMLImage img = new IHTMLImage();
                    img.AttachTo(c);
                    lastPicture = pic;
                    img.src = pic.Avatar96frame1;
                    img.style.left = "-150px";

                    await 500;

                    Native.window.requestAnimationFrame += delegate
                    {
                        img.style.left = "50px";

                    };

                    await 10000;

                    Native.window.requestAnimationFrame += delegate
                    {
                        img.style.left = "-150px";

                    };
                }
                await 4000;
            }

        }