/// <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 f = new ConsoleForm();

            f.InitializeConsoleFormWriter();
            f.Show();

            // shard across browsers in the same session?
            var session = new Cookie("session").DefaultToRandomInt32();
            //Native.Window.localStorage

            var random = new Cookie("random").DefaultToRandomInt32();


            Console.WriteLine("\n Console has been redirected!");
            Console.WriteLine("\n " + new { session = session.IntegerValue.ToString("x8") });

            #region WaitInHandler
            page.WaitInHandler.onclick +=
                delegate
                {
                    page.WaitInHandler.disabled = true;
                    new IXMLHttpRequest(
                        url: "/wait",
                        handler: r =>
                            {
                                page.WaitInHandler.disabled = false;

                            }
                    );
                };
            #endregion

            page.CheckDatabase.onclick +=
                delegate
                {
                    service.CheckDatabase("",
                        Console.WriteLine
                    );

                };

            #region CheckServerForSession
            page.CheckServerForSession.onclick +=
                delegate
                {
                    page.CheckServerForSession.disabled = true;

                    service.CheckServerForSession("" + session.IntegerValue,
                        x =>
                        {
                            Console.WriteLine(x);
                            page.CheckServerForSession.disabled = false;
                        }
                    );
                };
            #endregion

            page.DoLongOperation.onclick +=
                delegate
                {
                    page.DoLongOperation.disabled = true;

                    // can we send IEvent as argument directly?
                    // can we set a field on client side and have
                    // it updated on each call?
                    service.DoLongOperation("" + session.IntegerValue,
                        delegate
                        {
                            page.DoLongOperation.disabled = false;

                        }
                    );
                };

            #region UseCurrentIdToGetOutput
            page.UseCurrentIdToGetOutput.disabled = true;

            // enable while clickonce is active
            page.GetCurrentIdToStartListening.onclick +=
                delegate
                {
                    page.GetCurrentIdToStartListening.disabled = true;

                    service.SelectTransactionKey(
                        "" + session.IntegerValue,
                        id =>
                        {
                            Console.WriteLine(new { id });
                            page.UseCurrentIdToGetOutput.disabled = false;

                            page.UseCurrentIdToGetOutput.onclick +=
                                delegate
                                {
                                    page.UseCurrentIdToGetOutput.disabled = true;



                                    service.SelectContentUpdates(
                                        "" + session.IntegerValue,
                                        id,
                                        y: Console.Write,
                                        ynextid: nextid =>
                                        {
                                            id = nextid;

                                            Console.WriteLine(new { id });
                                            page.UseCurrentIdToGetOutput.disabled = false;
                                        }
                                    );

                                };
                        }
                     );

                };
            #endregion


            #region StartServerSentEvents
            page.StopServerSentEvents.disabled = true;

            page.StartServerSentEvents.onclick +=
                delegate
                {
                    page.StartServerSentEvents.disabled = true;



                    page.StopServerSentEvents.disabled = false;

                    //var n = new XElement("e",
                    //      new XAttribute("session", "" + session.IntegerValue)
                    //);

                    //var q = new StringBuilder();

                    //q.Append("/xml");
                    ////q.Append("?");

                    ////q.Append("e=" + n.ToString());


                    // Web Console(12961): Uncaught ReferenceError: EventSource is not defined at http://192.168.1.100:14690/view-source:46617
                    var s = new EventSource("/stream");

                    s["SystemConsoleOut"] =
                        e =>
                        {
                            //Console.WriteLine(new { SystemConsoleOut = new { e.lastEventId, e.data } });
                            Console.Write(((string)e.data)
                                .Replace("\\n", "\n")
                                .Replace("\\r", "\r")
                                );
                        };

                    s.onerror +=
                       e =>
                       {

                           //Console.WriteLine(new { onerror = new { s.readyState } });

                           if (s.readyState == 2)
                           {
                               // why are we getting that error??

                               s = null;

                               page.StartServerSentEvents.disabled = false;
                               page.StopServerSentEvents.disabled = true;
                           }
                       };

                    page.StopServerSentEvents.onclick +=
                        delegate
                        {
                            if (s == null)
                                return;

                            s.close();
                            s = null;

                            page.StartServerSentEvents.disabled = false;
                            page.StopServerSentEvents.disabled = true;

                        };

                };
            #endregion


            page.ChangeSessionTo.innerText = "session " + session.IntegerValue.ToString("x8");
        }
        public static void InvokeSpecial(this ApplicationWebService service, XElement e, Action<XElement> y)
        {
            var q = new StringBuilder();

            //q.Append("/event-stream");
            q.Append("?");

            q.Append("e=" + e.ToString());

            var s = new EventSource(q.ToString());

            s["y"] = a =>
            {


                var data = a.data.ToString()
                    .Replace("\\r", "\r")
                    .Replace("\\n", "\n");

                Console.WriteLine(new { data });

                var _y = XElement.Parse(data);

                y(_y);
            };

            s.onerror +=
                delegate
                {
                    s.close();
                };

        }
        public static void async_WebMethod2(this ApplicationWebService x, string e, Action<string> y)
        {
            var q = new StringBuilder();

            //q.Append("/event-stream");
            q.Append("?");

            q.Append("e=" + e);

            var s = new EventSource(q.ToString());

            s["y"] = a =>
            {


                var data = a.data.ToString()
                    .Replace("\\r", "\r")
                    .Replace("\\n", "\n");

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

                //var _y = XElement.Parse(data);

                y(data);
            };

            s.onerror +=
                delegate
                {
                    s.close();
                };
        }
        public static void sync_SelectContentUpdates_EventStream(this ApplicationWebService service, string last_id, Action<XElement> yield, Action<string> yield_last_id)
        {
            // this is on the client now!

            // some clients like IE do not support EventSource!
            // neither does AppEngine:P revert to iframe?


            // jsc might want to look at the features
            // an app is using
            // does the browser support svg, EventSource
            // does the server support event-stream?
            // if not show alternative app or error page
            // IE does not have pointerlock
            // android 2.2 stock browser has no svg!

            dynamic w = Native.window;
            IFunction EventSource = w.EventSource;

            if (EventSource == null)
            {
                // fallback
                service.sync_SelectContentUpdates(last_id, yield, yield_last_id);
                return;
            }

            #region EventSource
            //Console.WriteLine("enter EventSource");
            var s = new EventSource("/ApplicationWebService.sync.SelectContentUpdates?id=" + last_id);

            var id = last_id;

            s["yield"] =
                e =>
                {
                    id = e.lastEventId;

                    //Console.WriteLine(new { SystemConsoleOut = new { e.lastEventId, e.data } });
                    var value = (((string)e.data)
                        .Replace("\\n", "\n")
                        .Replace("\\r", "\r")
                        );

                    yield(XElement.Parse(value));
                };

            s.onmessage +=
                 e =>
                 {
                     id = e.lastEventId;
                 };

            s.onerror +=
                e =>
                {
                    //Console.WriteLine("exit EventSource " + new { id, s.readyState });
                    s.close();

                    yield_last_id(id);
                };
            #endregion




        }
        public static void add_NFCTagDiscovered(this ApplicationWebService service, Action<string> y)
        {
            var s = new EventSource();

            s["y"] = a =>
            {


                var data = a.data.ToString()
                    .Replace("\\r", "\r")
                    .Replace("\\n", "\n");


                y(data);
            };

            s.onerror +=
                delegate
                {
                    s.close();
                };

        }