/// <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)
        {

            // {{ permission = default }}
            new IHTMLPre { new { Notification.permission } }.AttachToDocument();

            // https://developer.mozilla.org/en-US/docs/Web/API/Notification/Using_Web_Notifications
            // default: the user didn't give any permission yet (and therefore no notification will be displayed to the user).

            new IHTMLButton { "requestPermission!" }.AttachToDocument().onclick +=
                delegate
            {
                // Uncaught TypeError: Failed to execute 'requestPermission' on 'Notification': The callback provided as parameter 1 is not a function.
                Notification.requestPermission(
                    new Action<string>(
                        p =>
                        {

                            new IHTMLPre { new { p } }.AttachToDocument();
                            // {{ p = granted }}
                        }
                    )
                );


            };

            new IHTMLButton { "do!" }.AttachToDocument().onclick +=
                delegate
            {
                var n = new Notification("hello world", options: new { sticky = true, icon = new HTML.Images.FromAssets.jsc().src });

                n.onclick += delegate
                {
                    new IHTMLPre { "onclick" }.AttachToDocument();
                };

                n.onclose += delegate
                {
                    new IHTMLPre { "onclose" }.AttachToDocument();
                };

            };
        }
        public Application(IApp page)
        {
            // jsc does not yet pre package chrome apps nor extensions
            // thus we do it manually.
            // https://sites.google.com/a/jsc-solutions.net/backlog/knowledge-base/2014/20140705/20140712
            // X:\jsc.svn\examples\javascript\chrome\extensions\ChromeTabsExperiment\ChromeTabsExperiment\Application.cs

            // A single extension can override only one page. For example, an extension can't override both the Bookmark Manager and History pages.


            // we could provide special API for scriptcorelib runtime on the tab being loaded
            // http://blog.chromium.org/

            // what else can we override besides options?
            // "options_page": "Application.htm",
            // https://code.google.com/p/chromium/issues/detail?id=171752
            // https://developer.chrome.com/extensions/options

            // can we provide an API about available android devices?

            #region self_chrome_tabs
            dynamic self = Native.self;
            dynamic self_chrome = self.chrome;
            object self_chrome_tabs = self_chrome.tabs;

            if (self_chrome_tabs != null)
            {
                #region Suspend
                chrome.runtime.Suspend += delegate
                  {
                      // dispose all injection done so far?
                      Console.WriteLine("chrome.runtime.Suspend");
                  };
                #endregion


                // jsc, add chrome nuget
                #region Installed
                chrome.runtime.Installed += delegate
                {
                    // our API does not have a Show
                    new chrome.Notification
                    {
                        Message = "Extension Installed!"
                    };
                };
                #endregion

                Action<string> AtMessageFromTabToExtensionForApplication = delegate { };

                Action<string> AtUDPString = delegate { };

                var IgnoreSecondaryUpdatesFor = new List<TabIdInteger>();

                #region Updated
                chrome.tabs.Updated +=
                    async (i, x, tab) =>
                    {
                        // chrome://newtab/

                        if (tab.url.StartsWith("chrome-devtools://"))
                            return;

                        if (tab.url.StartsWith("chrome://"))
                            return;

                        if (tab.status != "complete")
                            return;


                        if (IgnoreSecondaryUpdatesFor.Contains(tab.id))
                            return;

                        // inject?

                        // what if we sent the uri to our android tab?
                        var n = new Notification
                        {
                            Message = "Updated! " + new { tab.id, tab.url }
                        };

                        IgnoreSecondaryUpdatesFor.Add(tab.id);



                        // X:\jsc.svn\core\ScriptCoreLib\JavaScript\BCLImplementation\System\Net\WebClient.cs

                        //var aFileParts = new[] { code };
                        //var oMyBlob = new Blob(aFileParts, new { type = "text/javascript" }); // the blob
                        //var url = oMyBlob.ToObjectURL();

                        //Console.WriteLine(new { url });


                        // when will roslyn learn to expose events as async?
                        await tab.pageAction.async.onclick;

                        var nn = new Notification
                        {
                            Message = "Clicked " + new { tab.id, tab.url }
                        };



                        var code = await new WebClient().DownloadStringTaskAsync(
                             new Uri(Worker.ScriptApplicationSource, UriKind.Relative)
                        );


                        //Console.WriteLine("before insertCSS");

                        // https://developer.chrome.com/extensions/tabs#type-Tab
                        // http://stackoverflow.com/questions/9795058/how-to-run-chrome-tabs-insertcss-from-the-background-page-on-each-page
                        // chrome::
                        tab.id.insertCSS(
                            new
                            {
                                // .css do we have a CSS parser/builder available yet?

                                //code = "body { border: 1em solid red; }"
                                code = "body { border-left: 1em solid yellow; }"
                            },
                            null
                        );

                        // await tab.id.Run(async delegate {});
                        //};


                        // Unchecked runtime.lastError while running tabs.executeScript: No source code or file specified.
                        // https://developer.chrome.com/extensions/tabs#method-executeScript
                        // https://developer.chrome.com/extensions/tabs#type-InjectDetails
                        // https://developer.chrome.com/extensions/content_scripts#pi

                        // Content scripts execute in a special environment called an isolated world. 
                        // They have access to the DOM of the page they are injected into, but not to any JavaScript variables or 
                        // functions created by the page. It looks to each content script as if there is no other JavaScript executing
                        // on the page it is running on. The same is true in reverse: JavaScript running on the page cannot call any 
                        // functions or access any variables defined by content scripts.

                        var result = await tab.id.executeScript(
                            //new { file = url }
                            new { code }
                        );




                        // how to use connect?
                        var p = tab.id.connect();
                        var p_disconnected = false;

                        p.onDisconnect.addListener(
                            new Action(
                                delegate
                                {
                                    p_disconnected = true;
                                }
                            )
                        );


                        p.onMessage.addListener(
                            new Action<string>(
                                data =>
                                {
                                    AtMessageFromTabToExtensionForApplication(data);

                                    //Console.WriteLine("extension: onMessage " + new { data });
                                    //new Notification
                                    //{
                                    //    Message = "extension onMessage: " + new { tab.id, data }
                                    //};
                                }
                            )
                        );


                        //p.postMessage("hello executeScript");


                        // lets enable workers within tab
                        p.postMessage(new { code });

                        AtUDPString +=
                            xml =>
                            {
                                //Console.WriteLine("extension: " + new { xml });

                                if (p_disconnected)
                                    return;

                                if (tab.active)
                                {
                                    // only if active tab?
                                    p.postMessage(new { xml });
                                }
                            };
                    };
                #endregion





                #region __MulticastListenExperiment

                // can this chrome.extension connect to a chrome app?
                var __MulticastListenExperiment = "aemlnmcokphbneegoefdckonejmknohh";

                Console.WriteLine("chrome.runtime.connect " + new { __MulticastListenExperiment });

                // what if the app is not loaded, or is inactive?

                chrome.runtime.connect(__MulticastListenExperiment).With(
                      port =>
                      {
                          // Uncaught TypeError: Cannot read property 'id' of undefined
                          Console.WriteLine("chrome.runtime.connect OK " + new { __MulticastListenExperiment, chrome.runtime.lastError });
                          // 0:60ms chrome.runtime.connect OK { __MulticastListenExperiment = aemlnmcokphbneegoefdckonejmknohh, lastError =  } 
                          //Console.WriteLine("chrome.runtime.connect OK " + new { __MulticastListenExperiment, chrome.runtime.lastError, port.sender.id });


                          port.onDisconnect.addListener(
                              new Action(
                                  delegate
                                  {
                                      Console.WriteLine("chrome.runtime.connect onDisconnect " + new { __MulticastListenExperiment });
                                  }
                              )
                          );

                          // we wont know if we got the connection...
                          port.onMessage.addListener(
                                new Action<object>(
                                    message =>
                                    {
                                        // %c0:182ms app to extension { message = hello from app }

                                        //Console.WriteLine("app to extension " + new { message, port.sender.id });
                                        Console.WriteLine("app to extension " + new { message });

                                        //var nn = new chrome.Notification
                                        //{
                                        //    Title = "app to extension",
                                        //    Message = new { message }.ToString(),
                                        //};

                                        AtUDPString((string)message);
                                    }
                                )
                            );

                          AtMessageFromTabToExtensionForApplication +=
                              message =>
                              {
                                  port.postMessage(message);
                              };
                      }
                  );
                #endregion


                //Console.WriteLine("chrome.runtime.connect exit " + new { __MulticastListenExperiment });

                return;
            }
            #endregion

            Native.body.style.borderTop = "1em solid yellow";

            // if we were injected by executeScript, how would we launch a worker now?

            // VM608:41423


            // https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
            //getFileName: if this function was defined in a script returns the name of the script

            //var xx = new Exception();

            //Console.WriteLine(new { xx.StackTrace });
            //0:46ms { StackTrace = Error
            //    at AgsABmfn8j_aa_bqCu59PrPg (http://192.168.43.252:12879/view-source:27498:56)


            //0:25ms { StackTrace = Error
            //    at AgsABmfn8j_aa_bqCu59PrPg (<anonymous>:27498:56)
            //    at mV1GtUeaNze1ZFoeDPNoHQ.type$mV1GtUeaNze1ZFoeDPNoHQ.AwAABkeaNze1ZFoeDPNoHQ (<anonymous>:59652:9)


            // can we atleast try to ask for the source?


            Action<string> Notify = delegate { };

            new xxAvatar().Create();



            #region go worker
            new IHTMLButton { 
                "go worker: ",
               (

                    // we can read our own data, and any other browser extension can too, encrypt it?
                    from x in new xxAvatar()
                    orderby x.Key descending
                    //select x.Tag
                    //select new  {x.Tag}
                    select new xxAvatarRow { Tag = x.Tag}
                ).FirstOrDefaultAsync()
            }.AttachToDocument().With(
            button =>
            {
                button.style.position = IStyle.PositionEnum.@fixed;
                button.style.left = "1em";
                button.style.bottom = "1em";
                //button.style.zIndex = 1000;
                button.style.zIndex = 10000;




                button.onclick +=
                    async e =>
                    {
                        e.Element.disabled = true;


                        button.innerText = "working... ";


                        // live updates from worker via DB.
                        button.Add(

                             () => (

                                // we can read our own data, and any other browser extension can too, encrypt it?
                                from xx in new xxAvatar()
                                orderby xx.Key descending
                                //select x.Tag
                                //select new  {x.Tag}
                                select new xxAvatarRow { Tag = xx.Tag }
                            ).FirstOrDefaultAsync()

                        );


                        Native.body.style.borderTop = "1em solid blue";


                        var scopedata1 = "enter";
                        var scopedata2 = "exit";

                        var x = await Task.Run(
                            async delegate
                            {
                                var s = Stopwatch.StartNew();



                                for (int index = 0; index < 10; index++)
                                {

                                    // does it show up?
                                    await new xxAvatar().InsertAsync(
                                        new xxAvatarRow
                                        {
                                            Tag = "tab worker! " + scopedata1 + new { index, s.ElapsedMilliseconds, Thread.CurrentThread.ManagedThreadId },
                                        }
                                    );

                                    Console.WriteLine(new { Thread.CurrentThread.ManagedThreadId });
                                    await Task.Delay(99);
                                }


                                // does it show up?
                                await new xxAvatar().InsertAsync(
                                    new xxAvatarRow
                                    {
                                        Tag = "tab worker! " + scopedata2 + new { s.ElapsedMilliseconds, Thread.CurrentThread.ManagedThreadId },
                                    }
                                );

                                return "webview worker calling extension " + new { s.ElapsedMilliseconds, Thread.CurrentThread.ManagedThreadId };
                            }
                        );


                        button.innerText = "go worker: ";


                        // live updates from worker via DB.
                        button.Add(

                            // show a static field, so we wont spam console
                             (

                                // we can read our own data, and any other browser extension can too, encrypt it?
                                from xx in new xxAvatar()
                                orderby xx.Key descending
                                //select x.Tag
                                //select new  {x.Tag}
                                select new xxAvatarRow { Tag = xx.Tag }
                            ).FirstOrDefaultAsync()

                        );

                        Notify(x);

                        Native.body.style.borderTop = "1em solid pink";
                        e.Element.disabled = false;
                    };




            }
            );
            #endregion



            var forms = new List<Form>();



            #region onxmlmessage
            Action<XElement> onxmlmessage = null;

            onxmlmessage =
                xml =>
                {
                    // we are working within another webapp
                    // the tab was told by the extension
                    // the extension was told by the app
                    // the app was told by udp broadcast
                    // that a jsc app is now running.

                    // cool.

                    // can we load it into here?

                    if (xml.Value.StartsWith("Visit me at "))
                    {
                        // what about android apps runnning on SSL?
                        // what about preview images?
                        // do we get localhost events too?

                        var uri = "http://" + xml.Value.SkipUntilOrEmpty("Visit me at ");

                        if (forms.Any(x => x.Text == uri))
                        {
                            // look already opened!
                            return;
                        }

                        // X:\jsc.internal.git\market\chrome\ChromeMyJscSolutionsNet\ChromeMyJscSolutionsNet\Application.cs

                        // "X:\jsc.svn\examples\javascript\android\com.abstractatech.appmanager\com.abstractatech.appmanager.sln"
                        // X:\jsc.svn\examples\javascript\android\com.abstractatech.appmanager\com.abstractatech.appmanager\Application.cs




                        // can we pop ourselves out of here too?
                        // can chrome>extensions do AppWindows?


                        // on some pages they style our div. shall we use a non div to get nonstyled element?
                        // or do we need shadow DOM? is it even available yet for us?
                        var f = new Form { Text = uri, ShowIcon = false };
                        forms.Add(f);

                        var w = new WebBrowser();
                        w.Dock = DockStyle.Fill;

                        f.Controls.Add(w);

                        w.Navigate(uri);
                        f.Show();

                        f.FormClosed +=
                            delegate
                            {
                                Console.WriteLine("FormClosed " + new { uri });

                                forms.Remove(f);

                            };

                        // if we close it we want it to be gone for good.
                        // the extension cannot detatch our frame. it may need to ask the app to reopen this virtual tab...
                        f.PopupInsteadOfClosing(HandleFormClosing: false,

                            SpecialCloseOnLeft:
                                delegate
                                {
                                    // shall we ask app:: to reopen uri in AppWindow?
                                    Notify(xml.ToString());

                                    f.Close();
                                }
                        );


                    }

                };
            #endregion


            #region Connect
            object self_chrome_runtime = self_chrome.runtime;
            Console.WriteLine(new { self_chrome_runtime });
            // 0:39ms { self_chrome_runtime = [object Object] }
            if (self_chrome_runtime != null)
            {
                chrome.runtime.Connect +=
                        e =>
                        {
                            // port
                            // extension connects to injected tab?
                            Console.WriteLine("chrome.runtime.Connect " + new { Native.document.domain });
                            //Console.WriteLine("chrome.runtime.Connect " + new { Native.document.domain, e.sender.id });

                            //0:123ms chrome.runtime.Connect
                            //0:126ms webview: onMessage { data = hello executeScript }


                            //http://stackoverflow.com/questions/15798516/is-there-an-event-for-when-a-chrome-extension-popup-is-closed


                            e.onDisconnect.addListener(
                                new Action(
                                    delegate
                                    {
                                        // extension unloaded
                                        Native.body.style.borderTop = "0em solid red";
                                        Native.body.style.borderLeft = "0em solid red";

                                        forms.WithEach(f => f.Close());

                                    }
                                )
                            );



                            e.onMessage.addListener(
                                new Action<dynamic>(
                                    data =>
                                    {
                                        string xml = data.xml;
                                        if (xml != null)
                                        {
                                            // tab injection was notified by extension, by app, by udp android?
                                            Native.body.style.borderLeft = "1em solid red";

                                            // 0:40394ms { xml = <string c="1">Visit me at 192.168.1.67:6169</string> }
                                            Console.WriteLine(new { xml });


                                            // X:\jsc.internal.git\market\chrome\ChromeMyJscSolutionsNet\ChromeMyJscSolutionsNet\Application.cs

                                            onxmlmessage(
                                                XElement.Parse(xml)
                                                );

                                        }

                                        string code = data.code;
                                        if (code != null)
                                        {

                                            //Console.WriteLine("webview: onMessage " + new { data });

                                            // %c0:41906ms extension: onMessage { data = connected! }
                                            //e.postMessage("got code! " + new { code.Length });

                                            Native.body.style.borderTop = "1em solid red";

                                            // InternalInlineWorker

                                            // http://stackoverflow.com/questions/21408510/chrome-cant-load-web-worker
                                            // this wont work for file:// tabs

                                            // message: "Failed to construct 'Worker': Script at 'blob:null/f544915f-b855-480b-8db8-bd6c686829b9#worker' cannot be accessed from origin 'null'."
                                            var aFileParts = new[] { code };
                                            var oMyBlob = new Blob(aFileParts, new { type = "text/javascript" }); // the blob
                                            var url = oMyBlob.ToObjectURL();

                                            InternalInlineWorker.ScriptApplicationSourceForInlineWorker = url;

                                            Notify = x =>
                                            {
                                                // Error in event handler for (unknown): Attempting to use a disconnected port object Stack trace: Error: Attempting to use a disconnected port object
                                                e.postMessage(x);
                                            };
                                        }
                                    }
                                )
                            );


                        };

                //chrome.runtime.Message +=
                //    delegate
                //    {
                //        Console.WriteLine("chrome.runtime.Message");
                //    };
            }
            #endregion





            // 0:168ms chrome.runtime.Connect
            // https://developer.chrome.com/extensions/tabs#method-sendMessage
            // chrome extension wont call here?
            //Native.window.onmessage +=
            //    e =>
            //    {
            //        Console.WriteLine(
            //            "onmessage: " +
            //            new { e.data }
            //        );




            //        e.postMessage("ok");

            //    };
        }
        /// <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)
        {
            // X:\jsc.svn\examples\javascript\chrome\apps\WebGL\ChromeAudi\Application.cs
            // X:\jsc.svn\examples\javascript\chrome\apps\MulticastListenExperiment\MulticastListenExperiment\Application.cs
            // X:\jsc.svn\examples\javascript\chrome\apps\ChromeNotificationExperiment\ChromeNotificationExperiment\Application.cs

            Console.WriteLine("hi!");


            #region += Launched chrome.app.window
            // X:\jsc.svn\examples\javascript\chrome\apps\ChromeTCPServerAppWindow\ChromeTCPServerAppWindow\Application.cs
            dynamic self = Native.self;
            dynamic self_chrome = self.chrome;
            object self_chrome_socket = self_chrome.socket;

            if (self_chrome_socket != null)
            {
                Action respawn = delegate { };
                // https://code.google.com/p/chromium/issues/detail?id=142450


                //new logo1
                #region AtUDPString
                var AtUDPString = default(Action<string>);

                AtUDPString =
                     async xmlstring =>
                     {
                         // X:\jsc.svn\examples\java\android\AndroidServiceUDPNotification\AndroidServiceUDPNotification\ApplicationActivity.cs
                         var xml = XElement.Parse(xmlstring);

                         if (xml.Value.StartsWith("Visit me at "))
                         {
                             // what about android apps runnning on SSL?
                             // what about preview images?
                             // do we get localhost events too?

                             var n = xml.Attribute("n");

                             var uri = "http://" + xml.Value.SkipUntilOrEmpty("Visit me at ");

                             respawn = delegate
                             {
                                 AtUDPString(xmlstring);
                             };

                             //var cnn = new ScriptCoreLib.JavaScript.DOM.Notification(
                             //    title: "" + n,

                             //      options: new
                             //      {
                             //          icon = new logo1().src
                             //      }
                             // );
                             //Task.Delay(8000).ContinueWith(x => cnn.close());


                             var cn = new chrome.Notification(
                                 //message: uri,
                                 title: "" + n,
                                 iconUrl: new logo1().src
                             );

                             await (Task)cn;
                             //await cnn.async.onclick;

                             Native.window.open(uri + "/results?search_query=" + n);


                         }

                     };
                #endregion


                //delegate
                //{

                //};
                ////chrome.
                //chrome.runtime.Installed +=


                var Activate = default(Action);

                Activate =
                    async delegate
                    {
                        // context analysis injection?
                        //caller.name;

                        // need to run once only
                        Activate = delegate { };

                        // can we start here and allow Launched event to toggle?

                        // https://code.google.com/p/cassia/
                        // http://stackoverflow.com/questions/18052282/sending-message-from-one-application-to-another-application-in-the-same-terminal

                        var gport = 40804;

                        respawn = delegate
                        {

                            var cnn = new ScriptCoreLib.JavaScript.DOM.Notification(
                                title: "awaiting for TV.. " + gport,

                                options: new
                                {
                                    icon = new logo1().src,
                                    body = "what interests you?"
                                }
                            );

                            Task.Delay(10000).ContinueWith(x => cnn.close());
                        };

                        respawn();


                        //  var n = new chrome.Notification(
                        //    title: "awaiting for TV..",
                        //    message: "TV could say hi about now..."

                        //);

                        var socket = await chrome.socket.create("udp", new object());
                        var socketId = socket.socketId;
                        var value_setMulticastTimeToLive = await socketId.setMulticastTimeToLive(30);
                        var value_bind = await socketId.bind("0.0.0.0", gport);
                        var value_joinGroup = await socketId.joinGroup("239.1.2.3");
                        var forever = true;

                        while (forever)
                        {
                            var result = await socketId.recvFrom(1048576);
                            if (result.resultCode < 0)
                                return;

                            byte[] source = new ScriptCoreLib.JavaScript.WebGL.Uint8ClampedArray(result.data);

                            var xml = Encoding.UTF8.GetString(source);

                            AtUDPString(xml);
                            // 52 bytes
                        }

                    };

                // make sure setup.exe and chrome.exe is closed if it seems stuck.

                // browser restart
                chrome.runtime.Startup +=
                    delegate { Activate(); };

                chrome.runtime.Installed +=
                    delegate { Activate(); };

                // if machine restarts, we never get launched?
                // Inspect views: background page (Inactive)

                chrome.app.runtime.Launched +=
                     async delegate
                     {
                         // re show the last data?

                         respawn();
                     };


            }

            #endregion

        }