/// <summary>
        /// Creates a Javascript execution environment
        /// </summary>
        /// <param name="fileContainer">The object that will be accessed through Javascript</param>
        /// <param name="javascriptContainer">The text file that contains the javascript</param>
        public ExecutionEnvironment(
            FileHandlerFactoryLocator fileHandlerFactoryLocator,
            IFileContainer javascriptContainer,
            IFileContainer fileContainer,
            SubProcess subProcess,
            ParentScope parentScope)
        {
            _FileHandlerFactoryLocator = fileHandlerFactoryLocator;
            _JavascriptContainer = javascriptContainer;
            _JavascriptLastModified = javascriptContainer.LastModified;

            parentScope.WebHandlersWithThisAsParent.Enqueue(fileContainer.WebHandler);

            object toDiscard;

            ISession ownerSession = FileHandlerFactoryLocator.SessionManagerHandler.CreateSession();

            try
            {
                if (null != fileContainer.Owner)
                    ownerSession.Login(fileContainer.Owner);

                IWebConnection ownerWebConnection = new BlockingShellWebConnection(
                    FileHandlerFactoryLocator.WebServer,
                    ownerSession,
                    fileContainer.FullPath,
                    null,
                    null,
                    new CookiesFromBrowser(),
                    CallingFrom.Web,
                    WebMethod.GET);

                ScopeWrapper = new ScopeWrapper(
                    fileHandlerFactoryLocator,
                    subProcess,
                    fileContainer,
                    parentScope,
                    ownerWebConnection,
                    out toDiscard);
            }
            catch (Exception e)
            {
                // If the Javascript has an error in it, it must be ignored.  If an error were returned, then malformed Javascript could hose the system!
                this._ExecutionEnvironmentErrors = e.ToString();
                log.Error("Error creating scope", e);
            }
            finally
            {
                FileHandlerFactoryLocator.SessionManagerHandler.EndSession(ownerSession.SessionId);
            }
        }
        /// <summary>
        /// Returns all of the script IDs for the class
        /// </summary>
        /// <param name="javascriptClass">The text handler that has the class's javascript</param>
        /// <param name="subProcess">The process that must have the given script loaded</param>
        /// <returns></returns>
        public ScopeInfo GetScopeInfoForClass(ITextHandler javascriptClass, SubProcess subProcess)
        {
            DateTime javascriptLastModified = javascriptClass.FileContainer.LastModified;

            ScopeInfo toReturn = null;
            using (TimedLock.Lock(ScopeInfoCache))
                ScopeInfoCache.TryGetValue(javascriptClass.FileContainer.FileId, out toReturn);

            if (null != toReturn)
                if (toReturn.JavascriptLastModified == javascriptLastModified)
                {
                    using (TimedLock.Lock(PrecompiledScriptDataByID))
                        foreach (int scriptID in toReturn.ScriptsAndIDsToBuildScope)
                            subProcess.LoadCompiled(
                                Thread.CurrentThread.ManagedThreadId,
                                PrecompiledScriptDataByID[scriptID],
                                scriptID);

                    return toReturn;
                }

            string javascript = javascriptClass.ReadAll();
            string fileType = null;
            List<int> scriptIDsToBuildScope = new List<int>();

            ISession ownerSession = FileHandlerFactoryLocator.SessionManagerHandler.CreateSession();

            try
            {
                ownerSession.Login(javascriptClass.FileContainer.Owner);

                IWebConnection ownerWebConnection = new BlockingShellWebConnection(
                    FileHandlerFactoryLocator.WebServer,
                    ownerSession,
                    javascriptClass.FileContainer.FullPath,
                    null,
                    null,
                    new CookiesFromBrowser(),
                    CallingFrom.Web,
                    WebMethod.GET);

                IEnumerable<ScriptAndMD5> dependantScriptsAndMD5s = FileHandlerFactoryLocator.WebServer.WebComponentResolver.DetermineDependantScripts(
                    GetRequiredScriptURLs(javascriptClass, out fileType),
                    ownerWebConnection);

                // Load static methods that are passed into the Javascript environment as-is
                Dictionary<string, MethodInfo> functionsInScope = SubProcessFactory.GetFunctionsForFileType(fileType);

                // Load all dependant scripts
                foreach (ScriptAndMD5 dependantScript in dependantScriptsAndMD5s)
                {
                    int scriptID = GetScriptID(
                        dependantScript.ScriptName + "___" + ownerSession.User.Identity,
                        dependantScript.MD5,
                        dependantScript.Script,
                        subProcess);

                    scriptIDsToBuildScope.Add(scriptID);
                }

                // Construct Javascript to shell to the "base" webHandler
                Set<Type> webHandlerTypes = new Set<Type>(FileHandlerFactoryLocator.WebHandlerPlugins);
                if (null != fileType)
                    webHandlerTypes.Add(FileHandlerFactoryLocator.WebHandlerClasses[fileType]);

                string baseWrapper = GetJavascriptWrapperForBase("base", webHandlerTypes);
                scriptIDsToBuildScope.Add(
                    GetScriptID(
                        javascriptClass.FileContainer.FullPath + "___" + "serversideBaseWrapper",
                        StringParser.GenerateMD5String(baseWrapper),
                        baseWrapper,
                        subProcess));

                // Get the ID for the actual javascript
                scriptIDsToBuildScope.Add(
                    GetScriptID(
                        javascriptClass.FileContainer.FullPath,
                        StringParser.GenerateMD5String(javascript),
                        javascript,
                        subProcess));

                // Add a little shunt to return information about the options
                scriptIDsToBuildScope.Add(
                    GetScriptID(
                        "____scopeshunt",
                        "xxx",
                        "\nif (this.options) options; else null;",
                        subProcess));

                toReturn = new ScopeInfo(
                    javascriptLastModified,
                    functionsInScope,
                    scriptIDsToBuildScope);

                using (TimedLock.Lock(ScopeInfoCache))
                    ScopeInfoCache[javascriptClass.FileContainer.FileId] = toReturn;

                return toReturn;
            }
            finally
            {
                FileHandlerFactoryLocator.SessionManagerHandler.EndSession(ownerSession.SessionId);
            }
        }
        private ParentScope CreateParentScope(IFileContainer javascriptContainer)
        {
            List<string> scriptsToEval = new List<string>();
            List<string> requestedScripts = new List<string>(new string[] { "/API/AJAX_serverside.js", "/API/json2.js" });

            string fileType = null;
            StringBuilder javascriptBuilder = new StringBuilder();
            foreach (string line in javascriptContainer.CastFileHandler<ITextHandler>().ReadLines())
            {
                // find file type
                if (line.Trim().StartsWith("// FileType:"))
                    fileType = line.Substring(12).Trim();

                // Find dependant scripts
                else if (line.Trim().StartsWith("// Scripts:"))
                    foreach (string script in line.Substring(11).Split(','))
                        requestedScripts.Add(script.Trim());

                else
                    javascriptBuilder.AppendFormat("{0}\n", line);
            }

            string javascript = javascriptBuilder.ToString();

            Dictionary<string, MethodInfo> functionsInScope = new Dictionary<string, MethodInfo>();
            List<KeyValuePair<IFileContainer, DateTime>> loadedScriptsModifiedTimes = new List<KeyValuePair<IFileContainer, DateTime>>();
            ISession ownerSession = FileHandlerFactoryLocator.SessionManagerHandler.CreateSession();

            try
            {
                ownerSession.Login(javascriptContainer.Owner);

                IWebConnection ownerWebConnection = new BlockingShellWebConnection(
                    FileHandlerFactoryLocator.WebServer,
                    ownerSession,
                    javascriptContainer.FullPath,
                    null,
                    null,
                    new CookiesFromBrowser(),
                    CallingFrom.Web,
                    WebMethod.GET);

                IEnumerable<ScriptAndMD5> dependantScriptsAndMD5s = FileHandlerFactoryLocator.WebServer.WebComponentResolver.DetermineDependantScripts(
                    requestedScripts,
                    ownerWebConnection);

                // Load static methods that are passed into the Javascript environment as-is
                foreach (Type javascriptFunctionsType in GetTypesThatHaveJavascriptFunctions(fileType))
                    foreach (MethodInfo method in javascriptFunctionsType.GetMethods(BindingFlags.Static | BindingFlags.Public))
                        functionsInScope[method.Name] = method;

                // Load all dependant scripts
                foreach (ScriptAndMD5 dependantScript in dependantScriptsAndMD5s)
                {
                    string scriptName = dependantScript.ScriptName;

                    if (scriptName.Contains("?"))
                        scriptsToEval.Add(ownerWebConnection.ShellTo(scriptName).ResultsAsString);
                    else
                    {
                        IFileContainer scriptFileContainer = FileHandlerFactoryLocator.FileSystemResolver.ResolveFile(scriptName);

                        if (scriptFileContainer.FileHandler is ITextHandler)
                        {
                            loadedScriptsModifiedTimes.Add(new KeyValuePair<IFileContainer, DateTime>(scriptFileContainer, scriptFileContainer.LastModified));
                            scriptsToEval.Add(scriptFileContainer.CastFileHandler<ITextHandler>().ReadAll());
                        }
                        else
                            scriptsToEval.Add(ownerWebConnection.ShellTo(scriptName).ResultsAsString);
                    }
                }

                loadedScriptsModifiedTimes.Add(new KeyValuePair<IFileContainer, DateTime>(javascriptContainer, javascriptContainer.LastModified));

                // Construct Javascript to shell to the "base" webHandler
                HashSet<Type> webHandlerTypes = new HashSet<Type>(FileHandlerFactoryLocator.WebHandlerPlugins);
                if (null != fileType)
                    webHandlerTypes.Add(FileHandlerFactoryLocator.WebHandlerClasses[fileType]);

                string baseWrapper = GetJavascriptWrapperForBase("base", webHandlerTypes);

                scriptsToEval.Add(baseWrapper);
                scriptsToEval.Add(javascript);
                scriptsToEval.Add("if (this.options) options; else null;");

                ParentScope parentScope = new ParentScope(loadedScriptsModifiedTimes, functionsInScope);

                Dictionary<string, object> data = new Dictionary<string, object>();
                data["Scripts"] = scriptsToEval;
                data["Functions"] = functionsInScope.Keys;

                _SubProcess.CreateParentScope(parentScope.ParentScopeId, Thread.CurrentThread.ManagedThreadId, data);
                return parentScope;
            }
            finally
            {
                FileHandlerFactoryLocator.SessionManagerHandler.EndSession(ownerSession.SessionId);
            }
        }
        /// <summary>
        /// Establishes trust between a user and another server
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="receiveNotificationEndpoint"></param>
        /// <param name="callback"></param>
        private void BeginEstablishTrust(
            IUserOrGroup sender,
            string receiveNotificationEndpoint,
            string establishTrustEndpoint,
            Action<string> callback,
            Action<Exception> errorCallback)
        {
            // Make sure the timer is created
            if (null == EstablishTrustDataTimer)
            {
                Timer timer = new Timer(EstablishTrustDataCleanup, null, 600000, 600000);
                if (null != Interlocked.CompareExchange<Timer>(ref EstablishTrustDataTimer, timer, null))
                    timer.Dispose();
            }

            // Get the avatar
            byte[] avatar;
            ISession session = FileHandlerFactoryLocator.SessionManagerHandler.CreateSession();

            try
            {
                IWebConnection webConnection = new BlockingShellWebConnection(
                    FileHandlerFactoryLocator.WebServer,
                    session,
                    "/Users/" + sender.Name + ".user?Method=GetAvatar",
                    null,
                    null,
                    null,
                    CallingFrom.Web,
                    WebMethod.GET);

                IWebResults webResults = webConnection.ShellTo("/Users/" + sender.Name + ".user?Method=GetAvatar");

                using (Stream stream = webResults.ResultsAsStream)
                {
                    avatar = new byte[stream.Length];
                    stream.Read(avatar, 0, avatar.Length);
                }
            }
            finally
            {
                FileHandlerFactoryLocator.SessionManagerHandler.EndSession(session.SessionId);
            }

            // Hold on to callback information for use after trust is established
            string token;
            using (TimedLock.Lock(EstablishTrustDatasByToken))
            {
                do
                    token = Convert.ToBase64String(SRandom.NextBytes(100));
                while (EstablishTrustDatasByToken.ContainsKey(token));

                EstablishTrustDatasByToken[token] = new EstablishTrustData();
            }

            HttpWebClient httpWebClient = new HttpWebClient();
            httpWebClient.BeginPost(
                establishTrustEndpoint,
                delegate(HttpResponseHandler httpResponseHandler)
                {
                    if (httpResponseHandler.StatusCode == System.Net.HttpStatusCode.Created)
                    {
                        string senderToken;

                        using (TimedLock.Lock(EstablishTrustDatasByToken))
                        {
                            senderToken = EstablishTrustDatasByToken[token].SenderToken;
                            EstablishTrustDatasByToken.Remove(token);
                        }

                        this.persistedUserManagerData.Write(userManagerData =>
                        {
                            var user = userManagerData.GetUser(sender.Id);

                            string oldSenderToken;
                            if (user.receiveNotificationSenderTokensByEndpoint.TryGetValue(receiveNotificationEndpoint, out oldSenderToken))
                                user.receiveNotificationEndpointsBySenderToken.Remove(oldSenderToken);

                            user.receiveNotificationEndpointsBySenderToken[senderToken] = receiveNotificationEndpoint;
                            user.receiveNotificationSenderTokensByEndpoint[receiveNotificationEndpoint] = senderToken;
                        });

                        callback(senderToken);
                    }
                    else
                        errorCallback(new ParticleException.CouldNotEstablishTrust("Couldn't establish trust: " + httpResponseHandler.AsString()));
                },
                errorCallback,
                new KeyValuePair<string, string>("senderIdentity", sender.Identity),
                new KeyValuePair<string, string>("token", token),
                new KeyValuePair<string, string>("avatar", Convert.ToBase64String(avatar)),
                new KeyValuePair<string, string>("loginURL", string.Format("http://{0}/Users/UserDB?Method=OpenIDLogin", FileHandlerFactoryLocator.HostnameAndPort)),
                new KeyValuePair<string, string>("loginURLOpenID", "openid_url"),
                new KeyValuePair<string, string>("loginURLWebFinger", "openid_url"),
                new KeyValuePair<string, string>("loginURLRedirect", "redirect"),
                GenerateSecurityTimestamp());
        }
        public IWebResults ShellTo(WebMethod method, string url, byte[] content, string contentType, CallingFrom callingFrom, bool bypassJavascript)
        {
            ShellWebConnection shellWebConnection = new BlockingShellWebConnection(
                this,
                method,
                url,
                content,
                contentType,
                _CookiesFromBrowser,
                callingFrom);

            shellWebConnection._BypassJavascript = bypassJavascript;

            return shellWebConnection.GenerateResultsForClient();
        }
        public IWebResults ShellTo(string url, CallingFrom callingFrom, bool bypassJavascript)
        {
            ShellWebConnection shellWebConnection = new BlockingShellWebConnection(
                url,
                this,
                PostParameters,
                _CookiesFromBrowser,
                callingFrom);

            shellWebConnection._BypassJavascript = bypassJavascript;

            return shellWebConnection.GenerateResultsForClient();
        }
        public IWebResults ShellTo(string url, IUser user)
        {
            ISession shellSession = new ShellSession(Session, user);

            ShellWebConnection shellWebConnection = new BlockingShellWebConnection(
                WebServer,
                shellSession,
                url,
                new byte[0],
                ContentType,
                CookiesFromBrowser,
                CallingFrom,
                WebMethod.GET);

            shellWebConnection._BypassJavascript = BypassJavascript;

            return shellWebConnection.GenerateResultsForClient();
        }
        public IWebConnection CreateShellConnection(IUser user)
        {
            ISession shellSession = new ShellSession(Session, user);

            ShellWebConnection shellWebConnection = new BlockingShellWebConnection(
                this,
                shellSession,
                RequestedFile,
                GetParameters,
                new byte[0],
                ContentType,
                CookiesFromBrowser,
                CallingFrom);

            shellWebConnection._BypassJavascript = BypassJavascript;

            return shellWebConnection;
        }
        private void LoadComponent(
            ITemplateParsingState templateParsingState,
            IDictionary<string, object> getParameters,
            XmlElement element)
        {
            XmlAttribute srcAttribute = (XmlAttribute)element.Attributes.GetNamedItem("src", templateParsingState.TemplateHandlerLocator.TemplatingConstants.TemplateNamespace);
            XmlAttribute urlAttribute = (XmlAttribute)element.Attributes.GetNamedItem("url", templateParsingState.TemplateHandlerLocator.TemplatingConstants.TemplateNamespace);

            // handle GET parameters
            // First, handle oc:getpassthrough
            IDictionary<string, object> myGetParameters;
            XmlAttribute getpassthroughAttribute = (XmlAttribute)element.Attributes.GetNamedItem("getpassthough", templateParsingState.TemplateHandlerLocator.TemplatingConstants.TemplateNamespace);
            if (null == getpassthroughAttribute)
            {
                myGetParameters = DictionaryFunctions.Create<string, object>(getParameters);
                myGetParameters.Remove("Method");
                myGetParameters.Remove("Action");
            }
            else
            {
                if ("false" == getpassthroughAttribute.Value)
                    myGetParameters = new Dictionary<string, object>();
                else
                {
                    myGetParameters = DictionaryFunctions.Create<string, object>(getParameters);
                    myGetParameters.Remove("Method");
                    myGetParameters.Remove("Action");
                }
            }

            // Next, pull out get parameters from the tag
            foreach (XmlAttribute attribute in element.Attributes)
                if ("" == attribute.NamespaceURI)
                    myGetParameters[attribute.LocalName] = attribute.Value;

            if ((null == srcAttribute) && (null == urlAttribute))
                // Remove empty components
                element.ParentNode.RemoveChild(element);

            else if ((null != srcAttribute) && (null != urlAttribute))
                templateParsingState.ReplaceNodes(
                    element,
                    templateParsingState.GenerateWarningNode("Either oc:src or oc:url can be specified; you can not choose both: " + element.OuterXml));

            else if (null != srcAttribute)
            {
                string fileName = templateParsingState.FileHandlerFactoryLocator.FileSystemResolver.GetAbsolutePath(
                    templateParsingState.GetCWD(element),
                    srcAttribute.Value);

                IFileContainer fileContainer;
                try
                {
                    fileContainer = templateParsingState.FileHandlerFactoryLocator.FileSystemResolver.ResolveFile(fileName);
                }
                catch (FileDoesNotExist fdne)
                {
                    log.Warn("An attempt was made to use a non-existant file in a template", fdne);

                    templateParsingState.ReplaceNodes(
                        element,
                        templateParsingState.GenerateWarningNode(fileName + " not found"));

                    return;
                }

                templateParsingState.WebConnection.TouchedFiles.Add(fileContainer);

                // If the user doesn't have permission for the component and the component has something to use instead, use it
                if (null == fileContainer.LoadPermission(templateParsingState.WebConnection.Session.User.Id) && element.HasChildNodes)
                {
                    XmlNode replacement = element.OwnerDocument.CreateElement("div");

                    foreach (XmlNode errorNode in element.ChildNodes)
                        replacement.AppendChild(errorNode);

                    element.ParentNode.InsertAfter(replacement, element);
                    element.ParentNode.RemoveChild(element);
                }
                else
                {
                    // If the user has permission, resolve the component and deal with default errors

                    XmlDocument componentDocument;

                    // TODO:  GET Parameters

                    try
                    {
                        componentDocument = templateParsingState.LoadXmlDocumentAndReplaceGetParameters(
                            myGetParameters,
                            fileContainer,
                            templateParsingState.GetXmlParseMode(element));

                        XmlNode firstChild = componentDocument.FirstChild;
                        XmlNodeList replacementNodes;
                        if ((firstChild.LocalName == "componentdef") && (firstChild.NamespaceURI == templateParsingState.TemplateHandlerLocator.TemplatingConstants.TemplateNamespace))
                            replacementNodes = firstChild.ChildNodes;
                        else
                            replacementNodes = componentDocument.ChildNodes;

                        templateParsingState.SetCWD(replacementNodes, fileContainer.ParentDirectoryHandler.FileContainer.FullPath);
                        templateParsingState.ReplaceNodes(element, replacementNodes);
                    }
                    catch (WebResultsOverrideException wroe)
                    {
                        templateParsingState.ReplaceNodes(
                            element,
                            templateParsingState.GenerateWarningNode(wroe.WebResults.ResultsAsString));
                    }
                    catch (Exception e)
                    {
                        log.Error("An error occured when loading a component", e);

                        templateParsingState.ReplaceNodes(
                            element,
                            templateParsingState.GenerateWarningNode("An unhandled error occured.  See the system logs for more information"));
                    }
                }
            }

            else if (null != urlAttribute)
            {
                XmlNode resultNode;
                string url = urlAttribute.Value;

                foreach (KeyValuePair<string, object> getParameter in myGetParameters)
                    url = HTTPStringFunctions.AppendGetParameter(url, getParameter.Key, getParameter.Value.ToString());

                try
                {
                    if (url.StartsWith("https://"))
                        resultNode = templateParsingState.GenerateWarningNode("https component nodes aren't supported due to certificate complexities");
                    else if (url.StartsWith("http://"))
                    {
                        HttpResponseHandler httpResponse = templateParsingState.WebConnection.Session.HttpWebClient.Get(url);

                        if ("text/xml" == httpResponse.ContentType)
                            resultNode =
                                templateParsingState.LoadXmlDocument("<html xmlns=\"" + templateParsingState.TemplateHandlerLocator.TemplatingConstants.HtmlNamespace + "\"><head></head><body>" + httpResponse.AsString() + "</body></html>", XmlParseMode.Xml, templateParsingState.GetCWD(element)).FirstChild.ChildNodes[1];
                        else
                            resultNode = element.OwnerDocument.CreateTextNode(httpResponse.AsString());
                    }
                    else
                        try
                        {
                            ShellWebConnection shellWebConnection = new BlockingShellWebConnection(
                                url,
                                templateParsingState.WebConnection,
                                null,
                                templateParsingState.WebConnection.CookiesFromBrowser);

                            IWebResults shellResults = shellWebConnection.GenerateResultsForClient();

                            if ("text/xml" == shellResults.ContentType)
                                resultNode =
                                    templateParsingState.LoadXmlDocument("<html xmlns=\"" + templateParsingState.TemplateHandlerLocator.TemplatingConstants.HtmlNamespace + "\"><head></head><body>" + shellResults.ResultsAsString + "</body></html>", XmlParseMode.Xml, templateParsingState.GetCWD(
                                    element)).FirstChild.ChildNodes[1];
                            else
                                resultNode = element.OwnerDocument.CreateTextNode(shellResults.ResultsAsString);
                        }
                        catch (WebResultsOverrideException wroe)
                        {
                            resultNode = templateParsingState.GenerateWarningNode(wroe.WebResults.ResultsAsString);
                        }
                }
                catch (Exception e)
                {
                    log.Error("An error occured when loading a component", e);
                    resultNode = templateParsingState.GenerateWarningNode("An unhandled error occured.  See the system logs for more information");
                }

                templateParsingState.ReplaceNodes(element, resultNode);
            }
        }
        /// <summary>
        /// Evaluates the specified template
        /// </summary>
        /// <param name="template"></param>
        /// <param name="arguments"></param>
        /// <returns></returns>
        public static IWebResults evaluateTemplate(string template, Dictionary<string, object> arguments)
        {
            if (null == template)
                template = "/DefaultTemplate/headerfooter.ochf";

            FunctionCallContext functionCallContext = FunctionCallContext.GetCurrentContext();

            IFileContainer templateEngineFileContainer = functionCallContext.ScopeWrapper.FileHandlerFactoryLocator.FileSystemResolver.ResolveFile("/System/TemplateEngine");
            ITemplateEngine templateEngineWebHandler = (ITemplateEngine)templateEngineFileContainer.WebHandler;

            RequestParameters requestParameters = new RequestParameters();

            if (null != arguments)
                foreach (KeyValuePair<string, object> requestParameter in (Dictionary<string, object>)arguments)
                    requestParameters.Add(requestParameter.Key, requestParameter.Value.ToString());

            IWebConnection webConnection = new BlockingShellWebConnection(
                functionCallContext.WebConnection,
                functionCallContext.WebConnection.Session,
                template,
                requestParameters,
                null,
                null,
                functionCallContext.WebConnection.CookiesFromBrowser,
                FunctionCaller.CallingFrom);

            return templateEngineWebHandler.Evaluate(webConnection, template);
        }