private string CreateNodeAnnotationContent(OpenNodeAnnotationEventArgs e)
        {
            var writer = new StringWriter();

            try
            {
                writer.WriteLine(DocumentationBrowserUtils.GetContentFromEmbeddedResource(STYLE_RESOURCE));

                // Get the Node info section
                var nodeDocumentation = NodeDocumentationHtmlGenerator.FromAnnotationEventArgs(e);
                writer.WriteLine(nodeDocumentation);

                // Convert the markdown file to html
                MarkdownHandlerInstance.ParseToHtml(ref writer, e.MinimumQualifiedName, e.PackageName);

                writer.Flush();
                var output = writer.ToString();

                // Sanitize html and warn if any changes where made
                if (MarkdownHandlerInstance.SanitizeHtml(ref output))
                {
                    LogWarning(Resources.ScriptTagsRemovalWarning, WarningLevel.Mild);
                }

                // inject the syntax highlighting script at the bottom at the document.
                output += DocumentationBrowserUtils.GetDPIScript();
                output += DocumentationBrowserUtils.GetSyntaxHighlighting();

                return(output);
            }
            finally
            {
                writer?.Dispose();
            }
        }
        /// <summary>
        /// Converts a markdown string into Html.
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="nodeNamespace"></param>
        /// <returns>Returns true if any script tags was removed from the string</returns>
        internal bool ParseToHtml(ref StringWriter writer, string nodeNamespace)
        {
            if (writer is null)
            {
                throw new ArgumentNullException(nameof(writer));
            }

            var mdFilePath = PackageDocumentationManager.Instance.GetAnnotationDoc(nodeNamespace);

            string mdString;
            bool   scriptTagsRemoved = false;

            if (string.IsNullOrWhiteSpace(mdFilePath) ||
                !File.Exists(mdFilePath))
            {
                mdString = DocumentationBrowserUtils.GetContentFromEmbeddedResource(NODE_ANNOTATION_NOT_FOUND);
            }

            else
            {
                // Doing this to avoid 'System.ObjectDisposedException'
                // https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2202?view=vs-2019
                Stream stream = null;
                try
                {
                    stream = File.Open(mdFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                    using (StreamReader reader = new StreamReader(stream))
                    {
                        stream   = null;
                        mdString = reader.ReadToEnd();
                    }
                }
                finally
                {
                    stream?.Dispose();
                }

                if (string.IsNullOrWhiteSpace(mdString))
                {
                    return(false);
                }

                // Remove scripts from user content for security reasons.
                if (SanitizeHtml(ref mdString))
                {
                    scriptTagsRemoved = true;
                }
            }

            var html = converter.ParseMd2Html(mdString, mdFilePath);

            writer.WriteLine(html);

            // inject the syntax highlighting script at the bottom at the document.
            writer.WriteLine(DocumentationBrowserUtils.GetDPIScript());
            writer.WriteLine(GetSyntaxHighlighting());

            return(scriptTagsRemoved);
        }
        private string LoadContentFromResources(string name, bool injectDPI = true, bool removeScriptTags = true)
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException(nameof(name));
            }

            string result;
            // If an assembly was specified in the uri, the resource will be searched there.
            Assembly assembly;
            var      assemblyIndex = name.LastIndexOf(";");

            if (assemblyIndex != -1)
            {
                var assemblyName = name.Substring(0, assemblyIndex);
                // Ignore version and public key, in case they were specified.
                var versionIndex = assemblyName.IndexOf(";");
                if (versionIndex != -1)
                {
                    assemblyName = assemblyName.Substring(0, versionIndex);
                }
                assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetName().Name == assemblyName);
                if (assembly == null)
                {
                    // The specified assembly is not loaded
                    return(null);
                }
                name = name.Substring(assemblyIndex + 1);
            }
            else
            {
                // Default to documentation browser assembly if no assembly was specified.
                assembly = GetType().Assembly;
            }

            Assembly resourceAssembly = GetResourceAssembly(assembly, name);

            var availableResources = resourceAssembly.GetManifestResourceNames();

            var matchingResource = availableResources
                                   .FirstOrDefault(str => str.EndsWith(name));

            if (string.IsNullOrEmpty(matchingResource))
            {
                // The resource might exist by a name that includes the culture name in it
                var nameWithCulture = GetResourceNameWithCultureName(name, resourceAssembly.GetName().CultureInfo);
                matchingResource = availableResources.FirstOrDefault(n => n.EndsWith(nameWithCulture));

                if (string.IsNullOrEmpty(matchingResource))
                {
                    return(null);
                }
            }

            Stream stream = null;

            try
            {
                stream = resourceAssembly.GetManifestResourceStream(matchingResource);
                using (StreamReader reader = new StreamReader(stream))
                {
                    result = reader.ReadToEnd();
                    stream = null;
                }
            }
            finally
            {
                if (stream != null)
                {
                    stream.Dispose();
                }
            }

            // Clean up possible script tags from document
            if (removeScriptTags &&
                MarkdownHandlerInstance.SanitizeHtml(ref result))
            {
                LogWarning(Resources.ScriptTagsRemovalWarning, WarningLevel.Mild);
            }

            //inject our DPI functions:
            if (injectDPI)
            {
                result += DocumentationBrowserUtils.GetDPIScript();
            }

            return(result);
        }