internal static TemplateDefinition FromManifest(string manifestUrl)
        {
            var httpContext  = HttpContext.Current;
            var cache        = httpContext.Cache;
            var manifestPath = httpContext.Server.MapPath(manifestUrl);

            var baseDef = cache[manifestPath] as TemplateDefinition;

            if (baseDef == null)
            {
                baseDef = new TemplateDefinition {
                    Folder = Path.GetDirectoryName(manifestUrl)
                };

                var xml = new XmlDocument {
                    XmlResolver = null
                };
                xml.Load(manifestPath);

                var resolver = new PathResolver(baseDef.Folder);

                // ReSharper disable PossibleNullReferenceException
                foreach (XmlNode node in xml.DocumentElement.ChildNodes)

                // ReSharper restore PossibleNullReferenceException
                {
                    if (node.NodeType == XmlNodeType.Element)
                    {
                        var elt = (XmlElement)node;
                        switch (elt.LocalName)
                        {
                        case "template":
                            baseDef.TemplateVirtualPath = GetResolvedPath(elt, resolver);
                            baseDef.TemplatePath        = httpContext.Server.MapPath(baseDef.TemplateVirtualPath);
                            break;

                        case "templateHead":
                            baseDef.TemplateHeadPath = httpContext.Server.MapPath(GetResolvedPath(elt, resolver));
                            break;

                        case "scripts":
                            foreach (XmlElement scriptElt in elt.GetElementsByTagName("script"))
                            {
                                var jsObject   = scriptElt.GetAttribute("jsObject");
                                var scriptPath = string.IsNullOrEmpty(scriptElt.InnerText.Trim())
                                                        ? string.Empty
                                                        : Globals.ResolveUrl(GetResolvedPath(scriptElt, resolver));
                                if (string.IsNullOrEmpty(jsObject))
                                {
                                    var jsLibraryName = scriptElt.GetAttribute("name");
                                    if (!string.IsNullOrEmpty(jsLibraryName))
                                    {
                                        SpecificVersion specificityTemp;
                                        SpecificVersion?specificity = null;
                                        Version         libraryVersion;
                                        if (!Version.TryParse(scriptElt.GetAttribute("version"), out libraryVersion))
                                        {
                                            libraryVersion = null;
                                        }
                                        else if (Enum.TryParse(scriptElt.GetAttribute("specificVersion"), true, out specificityTemp))
                                        {
                                            specificity = specificityTemp;
                                        }

                                        baseDef.ScriptLibraries[jsLibraryName] = Tuple.Create(libraryVersion, specificity);
                                        continue;
                                    }

                                    baseDef.ScriptUrls.Add(scriptPath);
                                    continue;
                                }

                                if (string.IsNullOrEmpty(scriptPath))
                                {
                                    // support legacy named jsObjects that map to libraries
                                    if (jsObject.Equals("jQuery"))
                                    {
                                        Version         libraryVersion = null;
                                        SpecificVersion?specificity    = null;
                                        baseDef.ScriptLibraries[CommonJs.jQuery]        = Tuple.Create(libraryVersion, specificity);
                                        baseDef.ScriptLibraries[CommonJs.jQueryMigrate] = Tuple.Create(libraryVersion, specificity);
                                    }
                                    else if (jsObject.Equals("jQuery.ui"))
                                    {
                                        Version         libraryVersion = null;
                                        SpecificVersion?specificity    = null;
                                        baseDef.ScriptLibraries[CommonJs.jQueryUI] = Tuple.Create(libraryVersion, specificity);
                                    }

                                    continue;
                                }

                                var script = CreateScript(jsObject, scriptPath);
                                if (!string.IsNullOrEmpty(script))
                                {
                                    baseDef.ScriptKeys.Add(jsObject);
                                    baseDef.Scripts.Add(jsObject, script);
                                }
                            }

                            break;

                        case "stylesheets":
                            foreach (XmlElement cssElt in elt.GetElementsByTagName("stylesheet"))
                            {
                                var cssPath = Globals.ResolveUrl(GetResolvedPath(cssElt, resolver));
                                baseDef.StyleSheets.Add(cssPath);
                            }

                            break;

                        case "defaultClientOptions":
                            foreach (XmlElement optionElt in elt.GetElementsByTagName("clientOption"))
                            {
                                var optionName  = optionElt.GetAttribute("name");
                                var optionType  = optionElt.GetAttribute("type");
                                var optionValue = optionElt.GetAttribute("value");
                                if (string.IsNullOrEmpty(optionType))
                                {
                                    optionType = "passthrough";
                                }

                                switch (optionType)
                                {
                                case "number":
                                    baseDef.DefaultClientOptions.Add(new ClientNumber(optionName, optionValue));
                                    break;

                                case "boolean":
                                    baseDef.DefaultClientOptions.Add(new ClientBoolean(optionName, optionValue));
                                    break;

                                case "string":
                                    baseDef.DefaultClientOptions.Add(new ClientString(optionName, optionValue));
                                    break;

                                default:
                                    baseDef.DefaultClientOptions.Add(new ClientOption(optionName, optionValue));
                                    break;
                                }
                            }

                            break;

                        case "defaultTemplateArguments":
                            foreach (XmlElement argElt in elt.GetElementsByTagName("templateArgument"))
                            {
                                var argName  = argElt.GetAttribute("name");
                                var argValue = argElt.GetAttribute("value");
                                baseDef.DefaultTemplateArguments.Add(new TemplateArgument(argName, argValue));
                            }

                            break;
                        }
                    }
                }

                foreach (var processor in DNNAbstract.SupportedTemplateProcessors())
                {
                    if (processor.LoadDefinition(baseDef))
                    {
                        baseDef.Processor = processor;
                        break;
                    }
                }

                if (baseDef.Processor == null)
                {
                    throw new ApplicationException(string.Format("Can't find processor for manifest {0}", manifestPath));
                }

                cache.Insert(manifestPath, baseDef, new CacheDependency(new[] { manifestPath, baseDef.TemplatePath }));
            }

            var result = baseDef.Clone();

            result.Reset();
            return(result);
        }
        internal static TemplateDefinition FromManifest(string manifestUrl)
        {
            var httpContext  = HttpContext.Current;
            var cache        = httpContext.Cache;
            var manifestPath = httpContext.Server.MapPath(manifestUrl);

            var baseDef = cache[manifestPath] as TemplateDefinition;

            if (baseDef == null)
            {
                baseDef = new TemplateDefinition {
                    Folder = Path.GetDirectoryName(manifestUrl)
                };

                var xml = new XmlDocument();
                xml.Load(manifestPath);

                var resolver = new PathResolver(baseDef.Folder);

                // ReSharper disable PossibleNullReferenceException
                foreach (XmlNode node in xml.DocumentElement.ChildNodes)
                // ReSharper restore PossibleNullReferenceException
                {
                    if (node.NodeType == XmlNodeType.Element)
                    {
                        var elt = (XmlElement)node;
                        switch (elt.LocalName)
                        {
                        case "template":
                            baseDef.TemplateVirtualPath = GetResolvedPath(elt, resolver);
                            baseDef.TemplatePath        = httpContext.Server.MapPath(baseDef.TemplateVirtualPath);
                            break;

                        case "templateHead":
                            baseDef.TemplateHeadPath = httpContext.Server.MapPath(GetResolvedPath(elt, resolver));
                            break;

                        case "scripts":
                            foreach (XmlElement scriptElt in elt.GetElementsByTagName("script"))
                            {
                                var jsObject   = scriptElt.GetAttribute("jsObject");
                                var scriptPath = String.IsNullOrEmpty(scriptElt.InnerText.Trim())
                                                                                                ? ""
                                                                                                : Globals.ResolveUrl(GetResolvedPath(scriptElt, resolver));
                                var key    = String.IsNullOrEmpty(jsObject) ? scriptPath : jsObject;
                                var script = CreateScript(jsObject, scriptPath);
                                if (!String.IsNullOrEmpty(script))
                                {
                                    baseDef.ScriptKeys.Add(key);
                                    baseDef.Scripts.Add(key, script);
                                }
                            }
                            break;

                        case "stylesheets":
                            foreach (XmlElement cssElt in elt.GetElementsByTagName("stylesheet"))
                            {
                                var cssPath = Globals.ResolveUrl(GetResolvedPath(cssElt, resolver));
                                baseDef.StyleSheets.Add(cssPath);
                            }
                            break;

                        case "defaultClientOptions":
                            foreach (XmlElement optionElt in elt.GetElementsByTagName("clientOption"))
                            {
                                var optionName  = optionElt.GetAttribute("name");
                                var optionType  = optionElt.GetAttribute("type");
                                var optionValue = optionElt.GetAttribute("value");
                                if (String.IsNullOrEmpty(optionType))
                                {
                                    optionType = "passthrough";
                                }
                                switch (optionType)
                                {
                                case "number":
                                    baseDef.DefaultClientOptions.Add(new ClientNumber(optionName, optionValue));
                                    break;

                                case "boolean":
                                    baseDef.DefaultClientOptions.Add(new ClientBoolean(optionName, optionValue));
                                    break;

                                case "string":
                                    baseDef.DefaultClientOptions.Add(new ClientString(optionName, optionValue));
                                    break;

                                default:
                                    baseDef.DefaultClientOptions.Add(new ClientOption(optionName, optionValue));
                                    break;
                                }
                            }
                            break;

                        case "defaultTemplateArguments":
                            foreach (XmlElement argElt in elt.GetElementsByTagName("templateArgument"))
                            {
                                var argName  = argElt.GetAttribute("name");
                                var argValue = argElt.GetAttribute("value");
                                baseDef.DefaultTemplateArguments.Add(new TemplateArgument(argName, argValue));
                            }
                            break;
                        }
                    }
                }

                foreach (var processor in DNNAbstract.SupportedTemplateProcessors())
                {
                    if (processor.LoadDefinition(baseDef))
                    {
                        baseDef.Processor = processor;
                        break;
                    }
                }

                if (baseDef.Processor == null)
                {
                    throw new ApplicationException(String.Format("Can't find processor for manifest {0}", manifestPath));
                }

                cache.Insert(manifestPath, baseDef, new CacheDependency(new[] { manifestPath, baseDef.TemplatePath }));
            }

            var result = baseDef.Clone();

            result.Reset();
            return(result);
        }