Browse Source

8.5.15 release

David Benson 7 years ago
parent
commit
5a196db1ee
100 changed files with 29627 additions and 11 deletions
  1. 58 1
      ChangeLog
  2. 1 1
      VERSION
  3. 1 0
      etc/build/build.xml
  4. 9 9
      etc/mxgraph/mxClient.js
  5. 56 0
      etc/vsd/README.txt
  6. BIN
      etc/vsd/VsdConverter/.vs/VsdConverter/v15/.suo
  7. 0 0
      etc/vsd/VsdConverter/.vs/VsdConverter/v15/Server/sqlite3/db.lock
  8. BIN
      etc/vsd/VsdConverter/.vs/VsdConverter/v15/Server/sqlite3/storage.ide
  9. 1030 0
      etc/vsd/VsdConverter/.vs/config/applicationhost.config
  10. 31 0
      etc/vsd/VsdConverter/VsdConverter.sln
  11. 28 0
      etc/vsd/VsdConverter/VsdConverter/App_Start/BundleConfig.cs
  12. 13 0
      etc/vsd/VsdConverter/VsdConverter/App_Start/FilterConfig.cs
  13. 23 0
      etc/vsd/VsdConverter/VsdConverter/App_Start/RouteConfig.cs
  14. 24 0
      etc/vsd/VsdConverter/VsdConverter/App_Start/WebApiConfig.cs
  15. 79 0
      etc/vsd/VsdConverter/VsdConverter/ApplicationInsights.config
  16. 39 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ApiDescriptionExtensions.cs
  17. 113 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/App_Start/HelpPageConfig.cs
  18. 63 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Controllers/HelpController.cs
  19. 134 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/HelpPage.css
  20. 26 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/HelpPageAreaRegistration.cs
  21. 467 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/HelpPageConfigurationExtensions.cs
  22. 7 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/CollectionModelDescription.cs
  23. 14 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/ComplexTypeModelDescription.cs
  24. 6 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/DictionaryModelDescription.cs
  25. 15 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/EnumTypeModelDescription.cs
  26. 11 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/EnumValueDescription.cs
  27. 12 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/IModelDocumentationProvider.cs
  28. 9 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/KeyValuePairModelDescription.cs
  29. 16 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/ModelDescription.cs
  30. 451 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/ModelDescriptionGenerator.cs
  31. 18 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/ModelNameAttribute.cs
  32. 36 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/ModelNameHelper.cs
  33. 11 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/ParameterAnnotation.cs
  34. 21 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/ParameterDescription.cs
  35. 6 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/SimpleTypeModelDescription.cs
  36. 108 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Models/HelpPageApiModel.cs
  37. 444 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/SampleGeneration/HelpPageSampleGenerator.cs
  38. 172 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/SampleGeneration/HelpPageSampleKey.cs
  39. 41 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/SampleGeneration/ImageSample.cs
  40. 37 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/SampleGeneration/InvalidSample.cs
  41. 456 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/SampleGeneration/ObjectGenerator.cs
  42. 11 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/SampleGeneration/SampleDirection.cs
  43. 37 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/SampleGeneration/TextSample.cs
  44. 22 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/Api.cshtml
  45. 41 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/ApiGroup.cshtml
  46. 6 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/CollectionModelDescription.cshtml
  47. 3 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/ComplexTypeModelDescription.cshtml
  48. 4 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/DictionaryModelDescription.cshtml
  49. 24 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/EnumTypeModelDescription.cshtml
  50. 67 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/HelpPageApiModel.cshtml
  51. 4 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/ImageSample.cshtml
  52. 13 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/InvalidSample.cshtml
  53. 4 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/KeyValuePairModelDescription.cshtml
  54. 26 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/ModelDescriptionLink.cshtml
  55. 48 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/Parameters.cshtml
  56. 30 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/Samples.cshtml
  57. 3 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/SimpleTypeModelDescription.cshtml
  58. 6 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/TextSample.cshtml
  59. 38 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/Index.cshtml
  60. 19 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/ResourceModel.cshtml
  61. 12 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Shared/_Layout.cshtml
  62. 41 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Web.config
  63. 4 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/_ViewStart.cshtml
  64. 161 0
      etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/XmlDocumentationProvider.cs
  65. 17 0
      etc/vsd/VsdConverter/VsdConverter/Content/Site.css
  66. 6816 0
      etc/vsd/VsdConverter/VsdConverter/Content/bootstrap.css
  67. 20 0
      etc/vsd/VsdConverter/VsdConverter/Content/bootstrap.min.css
  68. 192 0
      etc/vsd/VsdConverter/VsdConverter/Controllers/ConverterController.cs
  69. 18 0
      etc/vsd/VsdConverter/VsdConverter/Controllers/HomeController.cs
  70. 1 0
      etc/vsd/VsdConverter/VsdConverter/Global.asax
  71. 23 0
      etc/vsd/VsdConverter/VsdConverter/Global.asax.cs
  72. 35 0
      etc/vsd/VsdConverter/VsdConverter/Properties/AssemblyInfo.cs
  73. 21 0
      etc/vsd/VsdConverter/VsdConverter/Properties/PublishProfiles/CustomProfile.pubxml
  74. 10 0
      etc/vsd/VsdConverter/VsdConverter/Properties/PublishProfiles/CustomProfile.pubxml.user
  75. 18 0
      etc/vsd/VsdConverter/VsdConverter/Properties/PublishProfiles/FolderProfile.pubxml
  76. 379 0
      etc/vsd/VsdConverter/VsdConverter/Properties/PublishProfiles/FolderProfile.pubxml.user
  77. 17 0
      etc/vsd/VsdConverter/VsdConverter/Properties/PublishProfiles/FolderProfile1.pubxml
  78. 385 0
      etc/vsd/VsdConverter/VsdConverter/Properties/PublishProfiles/FolderProfile1.pubxml.user
  79. 2014 0
      etc/vsd/VsdConverter/VsdConverter/Scripts/bootstrap.js
  80. 21 0
      etc/vsd/VsdConverter/VsdConverter/Scripts/bootstrap.min.js
  81. 2671 0
      etc/vsd/VsdConverter/VsdConverter/Scripts/jquery-1.10.2.intellisense.js
  82. 9803 0
      etc/vsd/VsdConverter/VsdConverter/Scripts/jquery-1.10.2.js
  83. 23 0
      etc/vsd/VsdConverter/VsdConverter/Scripts/jquery-1.10.2.min.js
  84. 1 0
      etc/vsd/VsdConverter/VsdConverter/Scripts/jquery-1.10.2.min.map
  85. 1416 0
      etc/vsd/VsdConverter/VsdConverter/Scripts/modernizr-2.6.2.js
  86. 340 0
      etc/vsd/VsdConverter/VsdConverter/Scripts/respond.js
  87. 20 0
      etc/vsd/VsdConverter/VsdConverter/Scripts/respond.min.js
  88. 30 0
      etc/vsd/VsdConverter/VsdConverter/Views/Home/Index.cshtml
  89. 13 0
      etc/vsd/VsdConverter/VsdConverter/Views/Shared/Error.cshtml
  90. 41 0
      etc/vsd/VsdConverter/VsdConverter/Views/Shared/_Layout.cshtml
  91. 43 0
      etc/vsd/VsdConverter/VsdConverter/Views/Web.config
  92. 3 0
      etc/vsd/VsdConverter/VsdConverter/Views/_ViewStart.cshtml
  93. 344 0
      etc/vsd/VsdConverter/VsdConverter/VsdConverter.csproj
  94. 46 0
      etc/vsd/VsdConverter/VsdConverter/VsdConverter.csproj.user
  95. 30 0
      etc/vsd/VsdConverter/VsdConverter/Web.Debug.config
  96. 31 0
      etc/vsd/VsdConverter/VsdConverter/Web.Release.config
  97. 75 0
      etc/vsd/VsdConverter/VsdConverter/Web.config
  98. BIN
      etc/vsd/VsdConverter/VsdConverter/favicon.ico
  99. BIN
      etc/vsd/VsdConverter/VsdConverter/fonts/glyphicons-halflings-regular.eot
  100. 0 0
      etc/vsd/VsdConverter/VsdConverter/fonts/glyphicons-halflings-regular.svg

+ 58 - 1
ChangeLog

@@ -1,4 +1,61 @@
-04-MAR-2018: 8.5.3
+01-MAY-2018: 8.5.15
+
+- Fixes showing device when no other storage options available
+- Fixes indexing with multiple diagrams on page in Confluence Cloud
+
+30-APR-2018: 8.5.14
+
+- Fixes XSS vulnerability in Trello Power-Up
+
+27-APR-2018: 8.5.13
+
+- Adds infographic library
+- Adds device option in export dialogs
+
+20-APR-2018: 8.5.12
+
+- Adds test case for Google auth errors
+
+20-APR-2018: 8.5.11
+
+- Fixes plantuml insert
+- Fixes PDF export size
+- Uses mxGraph 3.9.4 beta 4
+
+17-APR-2018: 8.5.10
+
+- Disables autosave for realtime connect errors
+- Fixes format panel background in dark theme
+- Adds click on export option labels
+- Adds namespace for CSV import
+- Changes help links in dialogs
+
+10-APR-2018: 8.5.9
+
+- Reverts macro inconsistency check for Confluence Cloud
+
+08-APR-2018: 8.5.8
+
+- Adds logging for disconnect error
+
+07-APR-2018: 8.5.7
+
+- Improved handling for Google disconnect error
+
+05-APR-2018: 8.5.6
+
+- Revert export server for Desktop version to phantom until full fix found
+
+05-APR-2018: 8.5.5
+
+- Changes Plant export URL
+- Adds JS redirect from http to https
+
+05-APR-2018: 8.5.4
+
+- Works around Chrome 65 bug with echo downloads
+
+04-APR-2018: 8.5.3
 
 - Gliffy import improvement
 - Fix for anchor download issue in Chrome 65

+ 1 - 1
VERSION

@@ -1 +1 @@
-8.5.3
+8.5.15

+ 1 - 0
etc/build/build.xml

@@ -125,6 +125,7 @@
 				<file name="Sidebar-GCP.js" />
 				<file name="Sidebar-Gmdl.js" />
 				<file name="Sidebar-IBM.js" />
+				<file name="Sidebar-Infographic.js" />
 				<file name="Sidebar-Ios.js" />
 				<file name="Sidebar-Ios7.js" />
 				<file name="Sidebar-LeanMapping.js" />

File diff suppressed because it is too large
+ 9 - 9
etc/mxgraph/mxClient.js


+ 56 - 0
etc/vsd/README.txt

@@ -0,0 +1,56 @@
+VsdConverterApp:
+
+C# Console App. It is a local TCP server that receives *.vsd files paths from clients and convert them to *.vsdx files using Visio.
+
+This application is needed to avoid security limitation that prevents this code from running inside IIS directly.  
+
+VsdConverter:
+
+AST.net web application that provides *.vsd files conversion service and acts as a client to the previous TCP server.
+
+========================================
+Running the conversion site:
+
+1- Run VsdConverterApp TCP sever
+2- Deploy VsdConverter to IIS (manually or using Web Deployment Tool).
+
+In details (Ignore Hyper-V steps if it is running directly on the server):
+
+Enable Hyper-V in Windows Features
+
+In Hyper-V Manager:
+
+1- Create a new virtual machine and select Windows 10 Dev
+	https://medium.com/@pugillum/setting-up-a-windows-server-2012-vm-on-windows-10-hyper-v-a23f854f34eb
+2- Install Visio in the VM
+	2.a Add Visio .iso file as a DVD
+	2.b Install from the DVD inside the VM normally
+	[OR] Download and istall Visio online
+3- Install IIS and enable ASP.NET
+	3.a Open Control Panel, Programs and Features, Turn Windows features on or off.
+	3.b Expand Internet Information Services, World Wide Web Services, and Application Development Features.
+	3.c Make sure that ASP.NET 4.7 is selected.
+4- After installing IIS, run IIS Manager to make sure that the .NET Framework version 4 is assigned to the default application pool.
+	4.a Press WINDOWS+R to open the Run dialog box.
+	4.b Enter "inetmgr", and then click OK.
+	4.c In the Connections pane, expand the server node and select Application Pools. In the Application Pools pane, if DefaultAppPool is assigned to the .NET framework version 4, skip to (5).
+	4.d In the Application Pools pane, click DefaultAppPool, and then in the Actions pane click Basic Settings.
+	4.e In the Edit Application Pool dialog box, change .NET Framework version to .NET Framework v4.0.30319 and click OK.
+	4.f IIS is now ready for you to publish a web application to it.
+5- Install Web Deploy https://technet.microsoft.com/en-us/library/dd569059.aspx --> x64 (64–bit) Web Deployment Tool (x64)
+	5.a Direct link: http://download.microsoft.com/download/8/9/B/89B754A5-56F7-45BD-B074-8974FD2039AF/WebDeploy_2_10_amd64_en-US.msi
+6- Open Control Panel\System and Security\System then Advanced system settings
+	6.a Advanced tab -> Environment Variables
+	6.b System variables -> Path -> Edit...
+	6.c New -> add the following: C:\Program Files\IIS\Microsoft Web Deploy V2
+	
+7- Open the command prompt (cmd) and change directory to the VsdConverter Package
+	7.a Run the deployment command: VsdConverter.deploy.cmd /Y
+8- In folder: C:\inetpub\wwwroot\VsdConverter_deploy
+	8.a create folder: App_Data
+	8.b Open Properties of App_Data -> Security -> Edit
+	8.c Give full control to Users: IIS_IUSRS
+9- Website is ready inside the VM: http://localhost/VsdConverter_deploy/
+	outside the VM by its ip which can be found using ipconfig (step 1)
+
+

BIN
etc/vsd/VsdConverter/.vs/VsdConverter/v15/.suo


+ 0 - 0
etc/vsd/VsdConverter/.vs/VsdConverter/v15/Server/sqlite3/db.lock


BIN
etc/vsd/VsdConverter/.vs/VsdConverter/v15/Server/sqlite3/storage.ide


File diff suppressed because it is too large
+ 1030 - 0
etc/vsd/VsdConverter/.vs/config/applicationhost.config


+ 31 - 0
etc/vsd/VsdConverter/VsdConverter.sln

@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27130.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VsdConverter", "VsdConverter\VsdConverter.csproj", "{61D7B18D-2DBB-411F-8854-7EAB3C226C37}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|x64 = Debug|x64
+		Release|Any CPU = Release|Any CPU
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{61D7B18D-2DBB-411F-8854-7EAB3C226C37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{61D7B18D-2DBB-411F-8854-7EAB3C226C37}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{61D7B18D-2DBB-411F-8854-7EAB3C226C37}.Debug|x64.ActiveCfg = Debug|x64
+		{61D7B18D-2DBB-411F-8854-7EAB3C226C37}.Debug|x64.Build.0 = Debug|x64
+		{61D7B18D-2DBB-411F-8854-7EAB3C226C37}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{61D7B18D-2DBB-411F-8854-7EAB3C226C37}.Release|Any CPU.Build.0 = Release|Any CPU
+		{61D7B18D-2DBB-411F-8854-7EAB3C226C37}.Release|x64.ActiveCfg = Release|x64
+		{61D7B18D-2DBB-411F-8854-7EAB3C226C37}.Release|x64.Build.0 = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {D52B51F9-7EF9-477D-8D0D-AC0F20AA9F99}
+	EndGlobalSection
+EndGlobal

+ 28 - 0
etc/vsd/VsdConverter/VsdConverter/App_Start/BundleConfig.cs

@@ -0,0 +1,28 @@
+using System.Web;
+using System.Web.Optimization;
+
+namespace VsdConverter
+{
+    public class BundleConfig
+    {
+        // For more information on bundling, visit https://go.microsoft.com/fwlink/?LinkId=301862
+        public static void RegisterBundles(BundleCollection bundles)
+        {
+            bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
+                        "~/Scripts/jquery-{version}.js"));
+
+            // Use the development version of Modernizr to develop with and learn from. Then, when you're
+            // ready for production, use the build tool at https://modernizr.com to pick only the tests you need.
+            bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
+                        "~/Scripts/modernizr-*"));
+
+            bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
+                      "~/Scripts/bootstrap.js",
+                      "~/Scripts/respond.js"));
+
+            bundles.Add(new StyleBundle("~/Content/css").Include(
+                      "~/Content/bootstrap.css",
+                      "~/Content/site.css"));
+        }
+    }
+}

+ 13 - 0
etc/vsd/VsdConverter/VsdConverter/App_Start/FilterConfig.cs

@@ -0,0 +1,13 @@
+using System.Web;
+using System.Web.Mvc;
+
+namespace VsdConverter
+{
+    public class FilterConfig
+    {
+        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
+        {
+            filters.Add(new HandleErrorAttribute());
+        }
+    }
+}

+ 23 - 0
etc/vsd/VsdConverter/VsdConverter/App_Start/RouteConfig.cs

@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+using System.Web.Mvc;
+using System.Web.Routing;
+
+namespace VsdConverter
+{
+    public class RouteConfig
+    {
+        public static void RegisterRoutes(RouteCollection routes)
+        {
+            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
+
+            routes.MapRoute(
+                name: "Default",
+                url: "{controller}/{action}/{id}",
+                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
+            );
+        }
+    }
+}

+ 24 - 0
etc/vsd/VsdConverter/VsdConverter/App_Start/WebApiConfig.cs

@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web.Http;
+
+namespace VsdConverter
+{
+    public static class WebApiConfig
+    {
+        public static void Register(HttpConfiguration config)
+        {
+            // Web API configuration and services
+
+            // Web API routes
+            config.MapHttpAttributeRoutes();
+
+            config.Routes.MapHttpRoute(
+                name: "DefaultApi",
+                routeTemplate: "api/{controller}/{id}",
+                defaults: new { id = RouteParameter.Optional }
+            );
+        }
+    }
+}

File diff suppressed because it is too large
+ 79 - 0
etc/vsd/VsdConverter/VsdConverter/ApplicationInsights.config


+ 39 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ApiDescriptionExtensions.cs

@@ -0,0 +1,39 @@
+using System;
+using System.Text;
+using System.Web;
+using System.Web.Http.Description;
+
+namespace VsdConverter.Areas.HelpPage
+{
+    public static class ApiDescriptionExtensions
+    {
+        /// <summary>
+        /// Generates an URI-friendly ID for the <see cref="ApiDescription"/>. E.g. "Get-Values-id_name" instead of "GetValues/{id}?name={name}"
+        /// </summary>
+        /// <param name="description">The <see cref="ApiDescription"/>.</param>
+        /// <returns>The ID as a string.</returns>
+        public static string GetFriendlyId(this ApiDescription description)
+        {
+            string path = description.RelativePath;
+            string[] urlParts = path.Split('?');
+            string localPath = urlParts[0];
+            string queryKeyString = null;
+            if (urlParts.Length > 1)
+            {
+                string query = urlParts[1];
+                string[] queryKeys = HttpUtility.ParseQueryString(query).AllKeys;
+                queryKeyString = String.Join("_", queryKeys);
+            }
+
+            StringBuilder friendlyPath = new StringBuilder();
+            friendlyPath.AppendFormat("{0}-{1}",
+                description.HttpMethod.Method,
+                localPath.Replace("/", "-").Replace("{", String.Empty).Replace("}", String.Empty));
+            if (queryKeyString != null)
+            {
+                friendlyPath.AppendFormat("_{0}", queryKeyString.Replace('.', '-'));
+            }
+            return friendlyPath.ToString();
+        }
+    }
+}

+ 113 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/App_Start/HelpPageConfig.cs

@@ -0,0 +1,113 @@
+// Uncomment the following to provide samples for PageResult<T>. Must also add the Microsoft.AspNet.WebApi.OData
+// package to your project.
+////#define Handle_PageResultOfT
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Net.Http.Headers;
+using System.Reflection;
+using System.Web;
+using System.Web.Http;
+#if Handle_PageResultOfT
+using System.Web.Http.OData;
+#endif
+
+namespace VsdConverter.Areas.HelpPage
+{
+    /// <summary>
+    /// Use this class to customize the Help Page.
+    /// For example you can set a custom <see cref="System.Web.Http.Description.IDocumentationProvider"/> to supply the documentation
+    /// or you can provide the samples for the requests/responses.
+    /// </summary>
+    public static class HelpPageConfig
+    {
+        [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters",
+            MessageId = "VsdConverter.Areas.HelpPage.TextSample.#ctor(System.String)",
+            Justification = "End users may choose to merge this string with existing localized resources.")]
+        [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly",
+            MessageId = "bsonspec",
+            Justification = "Part of a URI.")]
+        public static void Register(HttpConfiguration config)
+        {
+            //// Uncomment the following to use the documentation from XML documentation file.
+            //config.SetDocumentationProvider(new XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/XmlDocument.xml")));
+
+            //// Uncomment the following to use "sample string" as the sample for all actions that have string as the body parameter or return type.
+            //// Also, the string arrays will be used for IEnumerable<string>. The sample objects will be serialized into different media type 
+            //// formats by the available formatters.
+            //config.SetSampleObjects(new Dictionary<Type, object>
+            //{
+            //    {typeof(string), "sample string"},
+            //    {typeof(IEnumerable<string>), new string[]{"sample 1", "sample 2"}}
+            //});
+
+            // Extend the following to provide factories for types not handled automatically (those lacking parameterless
+            // constructors) or for which you prefer to use non-default property values. Line below provides a fallback
+            // since automatic handling will fail and GeneratePageResult handles only a single type.
+#if Handle_PageResultOfT
+            config.GetHelpPageSampleGenerator().SampleObjectFactories.Add(GeneratePageResult);
+#endif
+
+            // Extend the following to use a preset object directly as the sample for all actions that support a media
+            // type, regardless of the body parameter or return type. The lines below avoid display of binary content.
+            // The BsonMediaTypeFormatter (if available) is not used to serialize the TextSample object.
+            config.SetSampleForMediaType(
+                new TextSample("Binary JSON content. See http://bsonspec.org for details."),
+                new MediaTypeHeaderValue("application/bson"));
+
+            //// Uncomment the following to use "[0]=foo&[1]=bar" directly as the sample for all actions that support form URL encoded format
+            //// and have IEnumerable<string> as the body parameter or return type.
+            //config.SetSampleForType("[0]=foo&[1]=bar", new MediaTypeHeaderValue("application/x-www-form-urlencoded"), typeof(IEnumerable<string>));
+
+            //// Uncomment the following to use "1234" directly as the request sample for media type "text/plain" on the controller named "Values"
+            //// and action named "Put".
+            //config.SetSampleRequest("1234", new MediaTypeHeaderValue("text/plain"), "Values", "Put");
+
+            //// Uncomment the following to use the image on "../images/aspNetHome.png" directly as the response sample for media type "image/png"
+            //// on the controller named "Values" and action named "Get" with parameter "id".
+            //config.SetSampleResponse(new ImageSample("../images/aspNetHome.png"), new MediaTypeHeaderValue("image/png"), "Values", "Get", "id");
+
+            //// Uncomment the following to correct the sample request when the action expects an HttpRequestMessage with ObjectContent<string>.
+            //// The sample will be generated as if the controller named "Values" and action named "Get" were having string as the body parameter.
+            //config.SetActualRequestType(typeof(string), "Values", "Get");
+
+            //// Uncomment the following to correct the sample response when the action returns an HttpResponseMessage with ObjectContent<string>.
+            //// The sample will be generated as if the controller named "Values" and action named "Post" were returning a string.
+            //config.SetActualResponseType(typeof(string), "Values", "Post");
+        }
+
+#if Handle_PageResultOfT
+        private static object GeneratePageResult(HelpPageSampleGenerator sampleGenerator, Type type)
+        {
+            if (type.IsGenericType)
+            {
+                Type openGenericType = type.GetGenericTypeDefinition();
+                if (openGenericType == typeof(PageResult<>))
+                {
+                    // Get the T in PageResult<T>
+                    Type[] typeParameters = type.GetGenericArguments();
+                    Debug.Assert(typeParameters.Length == 1);
+
+                    // Create an enumeration to pass as the first parameter to the PageResult<T> constuctor
+                    Type itemsType = typeof(List<>).MakeGenericType(typeParameters);
+                    object items = sampleGenerator.GetSampleObject(itemsType);
+
+                    // Fill in the other information needed to invoke the PageResult<T> constuctor
+                    Type[] parameterTypes = new Type[] { itemsType, typeof(Uri), typeof(long?), };
+                    object[] parameters = new object[] { items, null, (long)ObjectGenerator.DefaultCollectionSize, };
+
+                    // Call PageResult(IEnumerable<T> items, Uri nextPageLink, long? count) constructor
+                    ConstructorInfo constructor = type.GetConstructor(parameterTypes);
+                    return constructor.Invoke(parameters);
+                }
+            }
+
+            return null;
+        }
+#endif
+    }
+}

+ 63 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Controllers/HelpController.cs

@@ -0,0 +1,63 @@
+using System;
+using System.Web.Http;
+using System.Web.Mvc;
+using VsdConverter.Areas.HelpPage.ModelDescriptions;
+using VsdConverter.Areas.HelpPage.Models;
+
+namespace VsdConverter.Areas.HelpPage.Controllers
+{
+    /// <summary>
+    /// The controller that will handle requests for the help page.
+    /// </summary>
+    public class HelpController : Controller
+    {
+        private const string ErrorViewName = "Error";
+
+        public HelpController()
+            : this(GlobalConfiguration.Configuration)
+        {
+        }
+
+        public HelpController(HttpConfiguration config)
+        {
+            Configuration = config;
+        }
+
+        public HttpConfiguration Configuration { get; private set; }
+
+        public ActionResult Index()
+        {
+            ViewBag.DocumentationProvider = Configuration.Services.GetDocumentationProvider();
+            return View(Configuration.Services.GetApiExplorer().ApiDescriptions);
+        }
+
+        public ActionResult Api(string apiId)
+        {
+            if (!String.IsNullOrEmpty(apiId))
+            {
+                HelpPageApiModel apiModel = Configuration.GetHelpPageApiModel(apiId);
+                if (apiModel != null)
+                {
+                    return View(apiModel);
+                }
+            }
+
+            return View(ErrorViewName);
+        }
+
+        public ActionResult ResourceModel(string modelName)
+        {
+            if (!String.IsNullOrEmpty(modelName))
+            {
+                ModelDescriptionGenerator modelDescriptionGenerator = Configuration.GetModelDescriptionGenerator();
+                ModelDescription modelDescription;
+                if (modelDescriptionGenerator.GeneratedModels.TryGetValue(modelName, out modelDescription))
+                {
+                    return View(modelDescription);
+                }
+            }
+
+            return View(ErrorViewName);
+        }
+    }
+}

+ 134 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/HelpPage.css

@@ -0,0 +1,134 @@
+.help-page h1,
+.help-page .h1,
+.help-page h2,
+.help-page .h2,
+.help-page h3,
+.help-page .h3,
+#body.help-page,
+.help-page-table th,
+.help-page-table pre,
+.help-page-table p {
+    font-family: "Segoe UI Light", Frutiger, "Frutiger Linotype", "Dejavu Sans", "Helvetica Neue", Arial, sans-serif;
+}
+
+.help-page pre.wrapped {
+    white-space: -moz-pre-wrap;
+    white-space: -pre-wrap;
+    white-space: -o-pre-wrap;
+    white-space: pre-wrap;
+}
+
+.help-page .warning-message-container {
+    margin-top: 20px;
+    padding: 0 10px;
+    color: #525252;
+    background: #EFDCA9; 
+    border: 1px solid #CCCCCC;
+}
+
+.help-page-table {
+    width: 100%;
+    border-collapse: collapse;
+    text-align: left;
+    margin: 0px 0px 20px 0px;
+    border-top: 1px solid #D4D4D4;
+}
+
+.help-page-table th {
+    text-align: left;
+    font-weight: bold;
+    border-bottom: 1px solid #D4D4D4;
+    padding: 5px 6px 5px 6px;
+}
+
+.help-page-table td {
+    border-bottom: 1px solid #D4D4D4;
+    padding: 10px 8px 10px 8px;
+    vertical-align: top;
+}
+
+.help-page-table pre,
+.help-page-table p {
+    margin: 0px;
+    padding: 0px;
+    font-family: inherit;
+    font-size: 100%;
+}
+
+.help-page-table tbody tr:hover td {
+    background-color: #F3F3F3;
+}
+
+.help-page a:hover {
+    background-color: transparent;
+}
+
+.help-page .sample-header {
+    border: 2px solid #D4D4D4;
+    background: #00497E;
+    color: #FFFFFF;
+    padding: 8px 15px;
+    border-bottom: none;
+    display: inline-block;
+    margin: 10px 0px 0px 0px;
+}
+
+.help-page .sample-content {
+    display: block;
+    border-width: 0;
+    padding: 15px 20px;
+    background: #FFFFFF;
+    border: 2px solid #D4D4D4;
+    margin: 0px 0px 10px 0px;
+}
+
+.help-page .api-name {
+    width: 40%;
+}
+
+.help-page .api-documentation {
+    width: 60%;
+}
+
+.help-page .parameter-name {
+    width: 20%;
+}
+
+.help-page .parameter-documentation {
+    width: 40%;
+}
+
+.help-page .parameter-type {
+    width: 20%;
+}
+
+.help-page .parameter-annotations {
+    width: 20%;
+}
+
+.help-page h1,
+.help-page .h1 {
+    font-size: 36px;
+    line-height: normal;
+}
+
+.help-page h2,
+.help-page .h2 {
+    font-size: 24px;
+}
+
+.help-page h3,
+.help-page .h3 {
+    font-size: 20px;
+}
+
+#body.help-page {
+    font-size: 14px;
+    line-height: 143%;
+    color: #333;
+}
+
+.help-page a {
+    color: #0000EE;
+    text-decoration: none;
+}

+ 26 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/HelpPageAreaRegistration.cs

@@ -0,0 +1,26 @@
+using System.Web.Http;
+using System.Web.Mvc;
+
+namespace VsdConverter.Areas.HelpPage
+{
+    public class HelpPageAreaRegistration : AreaRegistration
+    {
+        public override string AreaName
+        {
+            get
+            {
+                return "HelpPage";
+            }
+        }
+
+        public override void RegisterArea(AreaRegistrationContext context)
+        {
+            context.MapRoute(
+                "HelpPage_Default",
+                "Help/{action}/{apiId}",
+                new { controller = "Help", action = "Index", apiId = UrlParameter.Optional });
+
+            HelpPageConfig.Register(GlobalConfiguration.Configuration);
+        }
+    }
+}

+ 467 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/HelpPageConfigurationExtensions.cs

@@ -0,0 +1,467 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Web.Http;
+using System.Web.Http.Controllers;
+using System.Web.Http.Description;
+using VsdConverter.Areas.HelpPage.ModelDescriptions;
+using VsdConverter.Areas.HelpPage.Models;
+
+namespace VsdConverter.Areas.HelpPage
+{
+    public static class HelpPageConfigurationExtensions
+    {
+        private const string ApiModelPrefix = "MS_HelpPageApiModel_";
+
+        /// <summary>
+        /// Sets the documentation provider for help page.
+        /// </summary>
+        /// <param name="config">The <see cref="HttpConfiguration"/>.</param>
+        /// <param name="documentationProvider">The documentation provider.</param>
+        public static void SetDocumentationProvider(this HttpConfiguration config, IDocumentationProvider documentationProvider)
+        {
+            config.Services.Replace(typeof(IDocumentationProvider), documentationProvider);
+        }
+
+        /// <summary>
+        /// Sets the objects that will be used by the formatters to produce sample requests/responses.
+        /// </summary>
+        /// <param name="config">The <see cref="HttpConfiguration"/>.</param>
+        /// <param name="sampleObjects">The sample objects.</param>
+        public static void SetSampleObjects(this HttpConfiguration config, IDictionary<Type, object> sampleObjects)
+        {
+            config.GetHelpPageSampleGenerator().SampleObjects = sampleObjects;
+        }
+
+        /// <summary>
+        /// Sets the sample request directly for the specified media type and action.
+        /// </summary>
+        /// <param name="config">The <see cref="HttpConfiguration"/>.</param>
+        /// <param name="sample">The sample request.</param>
+        /// <param name="mediaType">The media type.</param>
+        /// <param name="controllerName">Name of the controller.</param>
+        /// <param name="actionName">Name of the action.</param>
+        public static void SetSampleRequest(this HttpConfiguration config, object sample, MediaTypeHeaderValue mediaType, string controllerName, string actionName)
+        {
+            config.GetHelpPageSampleGenerator().ActionSamples.Add(new HelpPageSampleKey(mediaType, SampleDirection.Request, controllerName, actionName, new[] { "*" }), sample);
+        }
+
+        /// <summary>
+        /// Sets the sample request directly for the specified media type and action with parameters.
+        /// </summary>
+        /// <param name="config">The <see cref="HttpConfiguration"/>.</param>
+        /// <param name="sample">The sample request.</param>
+        /// <param name="mediaType">The media type.</param>
+        /// <param name="controllerName">Name of the controller.</param>
+        /// <param name="actionName">Name of the action.</param>
+        /// <param name="parameterNames">The parameter names.</param>
+        public static void SetSampleRequest(this HttpConfiguration config, object sample, MediaTypeHeaderValue mediaType, string controllerName, string actionName, params string[] parameterNames)
+        {
+            config.GetHelpPageSampleGenerator().ActionSamples.Add(new HelpPageSampleKey(mediaType, SampleDirection.Request, controllerName, actionName, parameterNames), sample);
+        }
+
+        /// <summary>
+        /// Sets the sample request directly for the specified media type of the action.
+        /// </summary>
+        /// <param name="config">The <see cref="HttpConfiguration"/>.</param>
+        /// <param name="sample">The sample response.</param>
+        /// <param name="mediaType">The media type.</param>
+        /// <param name="controllerName">Name of the controller.</param>
+        /// <param name="actionName">Name of the action.</param>
+        public static void SetSampleResponse(this HttpConfiguration config, object sample, MediaTypeHeaderValue mediaType, string controllerName, string actionName)
+        {
+            config.GetHelpPageSampleGenerator().ActionSamples.Add(new HelpPageSampleKey(mediaType, SampleDirection.Response, controllerName, actionName, new[] { "*" }), sample);
+        }
+
+        /// <summary>
+        /// Sets the sample response directly for the specified media type of the action with specific parameters.
+        /// </summary>
+        /// <param name="config">The <see cref="HttpConfiguration"/>.</param>
+        /// <param name="sample">The sample response.</param>
+        /// <param name="mediaType">The media type.</param>
+        /// <param name="controllerName">Name of the controller.</param>
+        /// <param name="actionName">Name of the action.</param>
+        /// <param name="parameterNames">The parameter names.</param>
+        public static void SetSampleResponse(this HttpConfiguration config, object sample, MediaTypeHeaderValue mediaType, string controllerName, string actionName, params string[] parameterNames)
+        {
+            config.GetHelpPageSampleGenerator().ActionSamples.Add(new HelpPageSampleKey(mediaType, SampleDirection.Response, controllerName, actionName, parameterNames), sample);
+        }
+
+        /// <summary>
+        /// Sets the sample directly for all actions with the specified media type.
+        /// </summary>
+        /// <param name="config">The <see cref="HttpConfiguration"/>.</param>
+        /// <param name="sample">The sample.</param>
+        /// <param name="mediaType">The media type.</param>
+        public static void SetSampleForMediaType(this HttpConfiguration config, object sample, MediaTypeHeaderValue mediaType)
+        {
+            config.GetHelpPageSampleGenerator().ActionSamples.Add(new HelpPageSampleKey(mediaType), sample);
+        }
+
+        /// <summary>
+        /// Sets the sample directly for all actions with the specified type and media type.
+        /// </summary>
+        /// <param name="config">The <see cref="HttpConfiguration"/>.</param>
+        /// <param name="sample">The sample.</param>
+        /// <param name="mediaType">The media type.</param>
+        /// <param name="type">The parameter type or return type of an action.</param>
+        public static void SetSampleForType(this HttpConfiguration config, object sample, MediaTypeHeaderValue mediaType, Type type)
+        {
+            config.GetHelpPageSampleGenerator().ActionSamples.Add(new HelpPageSampleKey(mediaType, type), sample);
+        }
+
+        /// <summary>
+        /// Specifies the actual type of <see cref="System.Net.Http.ObjectContent{T}"/> passed to the <see cref="System.Net.Http.HttpRequestMessage"/> in an action.
+        /// The help page will use this information to produce more accurate request samples.
+        /// </summary>
+        /// <param name="config">The <see cref="HttpConfiguration"/>.</param>
+        /// <param name="type">The type.</param>
+        /// <param name="controllerName">Name of the controller.</param>
+        /// <param name="actionName">Name of the action.</param>
+        public static void SetActualRequestType(this HttpConfiguration config, Type type, string controllerName, string actionName)
+        {
+            config.GetHelpPageSampleGenerator().ActualHttpMessageTypes.Add(new HelpPageSampleKey(SampleDirection.Request, controllerName, actionName, new[] { "*" }), type);
+        }
+
+        /// <summary>
+        /// Specifies the actual type of <see cref="System.Net.Http.ObjectContent{T}"/> passed to the <see cref="System.Net.Http.HttpRequestMessage"/> in an action.
+        /// The help page will use this information to produce more accurate request samples.
+        /// </summary>
+        /// <param name="config">The <see cref="HttpConfiguration"/>.</param>
+        /// <param name="type">The type.</param>
+        /// <param name="controllerName">Name of the controller.</param>
+        /// <param name="actionName">Name of the action.</param>
+        /// <param name="parameterNames">The parameter names.</param>
+        public static void SetActualRequestType(this HttpConfiguration config, Type type, string controllerName, string actionName, params string[] parameterNames)
+        {
+            config.GetHelpPageSampleGenerator().ActualHttpMessageTypes.Add(new HelpPageSampleKey(SampleDirection.Request, controllerName, actionName, parameterNames), type);
+        }
+
+        /// <summary>
+        /// Specifies the actual type of <see cref="System.Net.Http.ObjectContent{T}"/> returned as part of the <see cref="System.Net.Http.HttpRequestMessage"/> in an action.
+        /// The help page will use this information to produce more accurate response samples.
+        /// </summary>
+        /// <param name="config">The <see cref="HttpConfiguration"/>.</param>
+        /// <param name="type">The type.</param>
+        /// <param name="controllerName">Name of the controller.</param>
+        /// <param name="actionName">Name of the action.</param>
+        public static void SetActualResponseType(this HttpConfiguration config, Type type, string controllerName, string actionName)
+        {
+            config.GetHelpPageSampleGenerator().ActualHttpMessageTypes.Add(new HelpPageSampleKey(SampleDirection.Response, controllerName, actionName, new[] { "*" }), type);
+        }
+
+        /// <summary>
+        /// Specifies the actual type of <see cref="System.Net.Http.ObjectContent{T}"/> returned as part of the <see cref="System.Net.Http.HttpRequestMessage"/> in an action.
+        /// The help page will use this information to produce more accurate response samples.
+        /// </summary>
+        /// <param name="config">The <see cref="HttpConfiguration"/>.</param>
+        /// <param name="type">The type.</param>
+        /// <param name="controllerName">Name of the controller.</param>
+        /// <param name="actionName">Name of the action.</param>
+        /// <param name="parameterNames">The parameter names.</param>
+        public static void SetActualResponseType(this HttpConfiguration config, Type type, string controllerName, string actionName, params string[] parameterNames)
+        {
+            config.GetHelpPageSampleGenerator().ActualHttpMessageTypes.Add(new HelpPageSampleKey(SampleDirection.Response, controllerName, actionName, parameterNames), type);
+        }
+
+        /// <summary>
+        /// Gets the help page sample generator.
+        /// </summary>
+        /// <param name="config">The <see cref="HttpConfiguration"/>.</param>
+        /// <returns>The help page sample generator.</returns>
+        public static HelpPageSampleGenerator GetHelpPageSampleGenerator(this HttpConfiguration config)
+        {
+            return (HelpPageSampleGenerator)config.Properties.GetOrAdd(
+                typeof(HelpPageSampleGenerator),
+                k => new HelpPageSampleGenerator());
+        }
+
+        /// <summary>
+        /// Sets the help page sample generator.
+        /// </summary>
+        /// <param name="config">The <see cref="HttpConfiguration"/>.</param>
+        /// <param name="sampleGenerator">The help page sample generator.</param>
+        public static void SetHelpPageSampleGenerator(this HttpConfiguration config, HelpPageSampleGenerator sampleGenerator)
+        {
+            config.Properties.AddOrUpdate(
+                typeof(HelpPageSampleGenerator),
+                k => sampleGenerator,
+                (k, o) => sampleGenerator);
+        }
+
+        /// <summary>
+        /// Gets the model description generator.
+        /// </summary>
+        /// <param name="config">The configuration.</param>
+        /// <returns>The <see cref="ModelDescriptionGenerator"/></returns>
+        public static ModelDescriptionGenerator GetModelDescriptionGenerator(this HttpConfiguration config)
+        {
+            return (ModelDescriptionGenerator)config.Properties.GetOrAdd(
+                typeof(ModelDescriptionGenerator),
+                k => InitializeModelDescriptionGenerator(config));
+        }
+
+        /// <summary>
+        /// Gets the model that represents an API displayed on the help page. The model is initialized on the first call and cached for subsequent calls.
+        /// </summary>
+        /// <param name="config">The <see cref="HttpConfiguration"/>.</param>
+        /// <param name="apiDescriptionId">The <see cref="ApiDescription"/> ID.</param>
+        /// <returns>
+        /// An <see cref="HelpPageApiModel"/>
+        /// </returns>
+        public static HelpPageApiModel GetHelpPageApiModel(this HttpConfiguration config, string apiDescriptionId)
+        {
+            object model;
+            string modelId = ApiModelPrefix + apiDescriptionId;
+            if (!config.Properties.TryGetValue(modelId, out model))
+            {
+                Collection<ApiDescription> apiDescriptions = config.Services.GetApiExplorer().ApiDescriptions;
+                ApiDescription apiDescription = apiDescriptions.FirstOrDefault(api => String.Equals(api.GetFriendlyId(), apiDescriptionId, StringComparison.OrdinalIgnoreCase));
+                if (apiDescription != null)
+                {
+                    model = GenerateApiModel(apiDescription, config);
+                    config.Properties.TryAdd(modelId, model);
+                }
+            }
+
+            return (HelpPageApiModel)model;
+        }
+
+        private static HelpPageApiModel GenerateApiModel(ApiDescription apiDescription, HttpConfiguration config)
+        {
+            HelpPageApiModel apiModel = new HelpPageApiModel()
+            {
+                ApiDescription = apiDescription,
+            };
+
+            ModelDescriptionGenerator modelGenerator = config.GetModelDescriptionGenerator();
+            HelpPageSampleGenerator sampleGenerator = config.GetHelpPageSampleGenerator();
+            GenerateUriParameters(apiModel, modelGenerator);
+            GenerateRequestModelDescription(apiModel, modelGenerator, sampleGenerator);
+            GenerateResourceDescription(apiModel, modelGenerator);
+            GenerateSamples(apiModel, sampleGenerator);
+
+            return apiModel;
+        }
+
+        private static void GenerateUriParameters(HelpPageApiModel apiModel, ModelDescriptionGenerator modelGenerator)
+        {
+            ApiDescription apiDescription = apiModel.ApiDescription;
+            foreach (ApiParameterDescription apiParameter in apiDescription.ParameterDescriptions)
+            {
+                if (apiParameter.Source == ApiParameterSource.FromUri)
+                {
+                    HttpParameterDescriptor parameterDescriptor = apiParameter.ParameterDescriptor;
+                    Type parameterType = null;
+                    ModelDescription typeDescription = null;
+                    ComplexTypeModelDescription complexTypeDescription = null;
+                    if (parameterDescriptor != null)
+                    {
+                        parameterType = parameterDescriptor.ParameterType;
+                        typeDescription = modelGenerator.GetOrCreateModelDescription(parameterType);
+                        complexTypeDescription = typeDescription as ComplexTypeModelDescription;
+                    }
+
+                    // Example:
+                    // [TypeConverter(typeof(PointConverter))]
+                    // public class Point
+                    // {
+                    //     public Point(int x, int y)
+                    //     {
+                    //         X = x;
+                    //         Y = y;
+                    //     }
+                    //     public int X { get; set; }
+                    //     public int Y { get; set; }
+                    // }
+                    // Class Point is bindable with a TypeConverter, so Point will be added to UriParameters collection.
+                    // 
+                    // public class Point
+                    // {
+                    //     public int X { get; set; }
+                    //     public int Y { get; set; }
+                    // }
+                    // Regular complex class Point will have properties X and Y added to UriParameters collection.
+                    if (complexTypeDescription != null
+                        && !IsBindableWithTypeConverter(parameterType))
+                    {
+                        foreach (ParameterDescription uriParameter in complexTypeDescription.Properties)
+                        {
+                            apiModel.UriParameters.Add(uriParameter);
+                        }
+                    }
+                    else if (parameterDescriptor != null)
+                    {
+                        ParameterDescription uriParameter =
+                            AddParameterDescription(apiModel, apiParameter, typeDescription);
+
+                        if (!parameterDescriptor.IsOptional)
+                        {
+                            uriParameter.Annotations.Add(new ParameterAnnotation() { Documentation = "Required" });
+                        }
+
+                        object defaultValue = parameterDescriptor.DefaultValue;
+                        if (defaultValue != null)
+                        {
+                            uriParameter.Annotations.Add(new ParameterAnnotation() { Documentation = "Default value is " + Convert.ToString(defaultValue, CultureInfo.InvariantCulture) });
+                        }
+                    }
+                    else
+                    {
+                        Debug.Assert(parameterDescriptor == null);
+
+                        // If parameterDescriptor is null, this is an undeclared route parameter which only occurs
+                        // when source is FromUri. Ignored in request model and among resource parameters but listed
+                        // as a simple string here.
+                        ModelDescription modelDescription = modelGenerator.GetOrCreateModelDescription(typeof(string));
+                        AddParameterDescription(apiModel, apiParameter, modelDescription);
+                    }
+                }
+            }
+        }
+
+        private static bool IsBindableWithTypeConverter(Type parameterType)
+        {
+            if (parameterType == null)
+            {
+                return false;
+            }
+
+            return TypeDescriptor.GetConverter(parameterType).CanConvertFrom(typeof(string));
+        }
+
+        private static ParameterDescription AddParameterDescription(HelpPageApiModel apiModel,
+            ApiParameterDescription apiParameter, ModelDescription typeDescription)
+        {
+            ParameterDescription parameterDescription = new ParameterDescription
+            {
+                Name = apiParameter.Name,
+                Documentation = apiParameter.Documentation,
+                TypeDescription = typeDescription,
+            };
+
+            apiModel.UriParameters.Add(parameterDescription);
+            return parameterDescription;
+        }
+
+        private static void GenerateRequestModelDescription(HelpPageApiModel apiModel, ModelDescriptionGenerator modelGenerator, HelpPageSampleGenerator sampleGenerator)
+        {
+            ApiDescription apiDescription = apiModel.ApiDescription;
+            foreach (ApiParameterDescription apiParameter in apiDescription.ParameterDescriptions)
+            {
+                if (apiParameter.Source == ApiParameterSource.FromBody)
+                {
+                    Type parameterType = apiParameter.ParameterDescriptor.ParameterType;
+                    apiModel.RequestModelDescription = modelGenerator.GetOrCreateModelDescription(parameterType);
+                    apiModel.RequestDocumentation = apiParameter.Documentation;
+                }
+                else if (apiParameter.ParameterDescriptor != null &&
+                    apiParameter.ParameterDescriptor.ParameterType == typeof(HttpRequestMessage))
+                {
+                    Type parameterType = sampleGenerator.ResolveHttpRequestMessageType(apiDescription);
+
+                    if (parameterType != null)
+                    {
+                        apiModel.RequestModelDescription = modelGenerator.GetOrCreateModelDescription(parameterType);
+                    }
+                }
+            }
+        }
+
+        private static void GenerateResourceDescription(HelpPageApiModel apiModel, ModelDescriptionGenerator modelGenerator)
+        {
+            ResponseDescription response = apiModel.ApiDescription.ResponseDescription;
+            Type responseType = response.ResponseType ?? response.DeclaredType;
+            if (responseType != null && responseType != typeof(void))
+            {
+                apiModel.ResourceDescription = modelGenerator.GetOrCreateModelDescription(responseType);
+            }
+        }
+
+        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "The exception is recorded as ErrorMessages.")]
+        private static void GenerateSamples(HelpPageApiModel apiModel, HelpPageSampleGenerator sampleGenerator)
+        {
+            try
+            {
+                foreach (var item in sampleGenerator.GetSampleRequests(apiModel.ApiDescription))
+                {
+                    apiModel.SampleRequests.Add(item.Key, item.Value);
+                    LogInvalidSampleAsError(apiModel, item.Value);
+                }
+
+                foreach (var item in sampleGenerator.GetSampleResponses(apiModel.ApiDescription))
+                {
+                    apiModel.SampleResponses.Add(item.Key, item.Value);
+                    LogInvalidSampleAsError(apiModel, item.Value);
+                }
+            }
+            catch (Exception e)
+            {
+                apiModel.ErrorMessages.Add(String.Format(CultureInfo.CurrentCulture,
+                    "An exception has occurred while generating the sample. Exception message: {0}",
+                    HelpPageSampleGenerator.UnwrapException(e).Message));
+            }
+        }
+
+        private static bool TryGetResourceParameter(ApiDescription apiDescription, HttpConfiguration config, out ApiParameterDescription parameterDescription, out Type resourceType)
+        {
+            parameterDescription = apiDescription.ParameterDescriptions.FirstOrDefault(
+                p => p.Source == ApiParameterSource.FromBody ||
+                    (p.ParameterDescriptor != null && p.ParameterDescriptor.ParameterType == typeof(HttpRequestMessage)));
+
+            if (parameterDescription == null)
+            {
+                resourceType = null;
+                return false;
+            }
+
+            resourceType = parameterDescription.ParameterDescriptor.ParameterType;
+
+            if (resourceType == typeof(HttpRequestMessage))
+            {
+                HelpPageSampleGenerator sampleGenerator = config.GetHelpPageSampleGenerator();
+                resourceType = sampleGenerator.ResolveHttpRequestMessageType(apiDescription);
+            }
+
+            if (resourceType == null)
+            {
+                parameterDescription = null;
+                return false;
+            }
+
+            return true;
+        }
+
+        private static ModelDescriptionGenerator InitializeModelDescriptionGenerator(HttpConfiguration config)
+        {
+            ModelDescriptionGenerator modelGenerator = new ModelDescriptionGenerator(config);
+            Collection<ApiDescription> apis = config.Services.GetApiExplorer().ApiDescriptions;
+            foreach (ApiDescription api in apis)
+            {
+                ApiParameterDescription parameterDescription;
+                Type parameterType;
+                if (TryGetResourceParameter(api, config, out parameterDescription, out parameterType))
+                {
+                    modelGenerator.GetOrCreateModelDescription(parameterType);
+                }
+            }
+            return modelGenerator;
+        }
+
+        private static void LogInvalidSampleAsError(HelpPageApiModel apiModel, object sample)
+        {
+            InvalidSample invalidSample = sample as InvalidSample;
+            if (invalidSample != null)
+            {
+                apiModel.ErrorMessages.Add(invalidSample.ErrorMessage);
+            }
+        }
+    }
+}

+ 7 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/CollectionModelDescription.cs

@@ -0,0 +1,7 @@
+namespace VsdConverter.Areas.HelpPage.ModelDescriptions
+{
+    public class CollectionModelDescription : ModelDescription
+    {
+        public ModelDescription ElementDescription { get; set; }
+    }
+}

+ 14 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/ComplexTypeModelDescription.cs

@@ -0,0 +1,14 @@
+using System.Collections.ObjectModel;
+
+namespace VsdConverter.Areas.HelpPage.ModelDescriptions
+{
+    public class ComplexTypeModelDescription : ModelDescription
+    {
+        public ComplexTypeModelDescription()
+        {
+            Properties = new Collection<ParameterDescription>();
+        }
+
+        public Collection<ParameterDescription> Properties { get; private set; }
+    }
+}

+ 6 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/DictionaryModelDescription.cs

@@ -0,0 +1,6 @@
+namespace VsdConverter.Areas.HelpPage.ModelDescriptions
+{
+    public class DictionaryModelDescription : KeyValuePairModelDescription
+    {
+    }
+}

+ 15 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/EnumTypeModelDescription.cs

@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+namespace VsdConverter.Areas.HelpPage.ModelDescriptions
+{
+    public class EnumTypeModelDescription : ModelDescription
+    {
+        public EnumTypeModelDescription()
+        {
+            Values = new Collection<EnumValueDescription>();
+        }
+
+        public Collection<EnumValueDescription> Values { get; private set; }
+    }
+}

+ 11 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/EnumValueDescription.cs

@@ -0,0 +1,11 @@
+namespace VsdConverter.Areas.HelpPage.ModelDescriptions
+{
+    public class EnumValueDescription
+    {
+        public string Documentation { get; set; }
+
+        public string Name { get; set; }
+
+        public string Value { get; set; }
+    }
+}

+ 12 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/IModelDocumentationProvider.cs

@@ -0,0 +1,12 @@
+using System;
+using System.Reflection;
+
+namespace VsdConverter.Areas.HelpPage.ModelDescriptions
+{
+    public interface IModelDocumentationProvider
+    {
+        string GetDocumentation(MemberInfo member);
+
+        string GetDocumentation(Type type);
+    }
+}

+ 9 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/KeyValuePairModelDescription.cs

@@ -0,0 +1,9 @@
+namespace VsdConverter.Areas.HelpPage.ModelDescriptions
+{
+    public class KeyValuePairModelDescription : ModelDescription
+    {
+        public ModelDescription KeyModelDescription { get; set; }
+
+        public ModelDescription ValueModelDescription { get; set; }
+    }
+}

+ 16 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/ModelDescription.cs

@@ -0,0 +1,16 @@
+using System;
+
+namespace VsdConverter.Areas.HelpPage.ModelDescriptions
+{
+    /// <summary>
+    /// Describes a type model.
+    /// </summary>
+    public abstract class ModelDescription
+    {
+        public string Documentation { get; set; }
+
+        public Type ModelType { get; set; }
+
+        public string Name { get; set; }
+    }
+}

+ 451 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/ModelDescriptionGenerator.cs

@@ -0,0 +1,451 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.ComponentModel.DataAnnotations;
+using System.Globalization;
+using System.Reflection;
+using System.Runtime.Serialization;
+using System.Web.Http;
+using System.Web.Http.Description;
+using System.Xml.Serialization;
+using Newtonsoft.Json;
+
+namespace VsdConverter.Areas.HelpPage.ModelDescriptions
+{
+    /// <summary>
+    /// Generates model descriptions for given types.
+    /// </summary>
+    public class ModelDescriptionGenerator
+    {
+        // Modify this to support more data annotation attributes.
+        private readonly IDictionary<Type, Func<object, string>> AnnotationTextGenerator = new Dictionary<Type, Func<object, string>>
+        {
+            { typeof(RequiredAttribute), a => "Required" },
+            { typeof(RangeAttribute), a =>
+                {
+                    RangeAttribute range = (RangeAttribute)a;
+                    return String.Format(CultureInfo.CurrentCulture, "Range: inclusive between {0} and {1}", range.Minimum, range.Maximum);
+                }
+            },
+            { typeof(MaxLengthAttribute), a =>
+                {
+                    MaxLengthAttribute maxLength = (MaxLengthAttribute)a;
+                    return String.Format(CultureInfo.CurrentCulture, "Max length: {0}", maxLength.Length);
+                }
+            },
+            { typeof(MinLengthAttribute), a =>
+                {
+                    MinLengthAttribute minLength = (MinLengthAttribute)a;
+                    return String.Format(CultureInfo.CurrentCulture, "Min length: {0}", minLength.Length);
+                }
+            },
+            { typeof(StringLengthAttribute), a =>
+                {
+                    StringLengthAttribute strLength = (StringLengthAttribute)a;
+                    return String.Format(CultureInfo.CurrentCulture, "String length: inclusive between {0} and {1}", strLength.MinimumLength, strLength.MaximumLength);
+                }
+            },
+            { typeof(DataTypeAttribute), a =>
+                {
+                    DataTypeAttribute dataType = (DataTypeAttribute)a;
+                    return String.Format(CultureInfo.CurrentCulture, "Data type: {0}", dataType.CustomDataType ?? dataType.DataType.ToString());
+                }
+            },
+            { typeof(RegularExpressionAttribute), a =>
+                {
+                    RegularExpressionAttribute regularExpression = (RegularExpressionAttribute)a;
+                    return String.Format(CultureInfo.CurrentCulture, "Matching regular expression pattern: {0}", regularExpression.Pattern);
+                }
+            },
+        };
+
+        // Modify this to add more default documentations.
+        private readonly IDictionary<Type, string> DefaultTypeDocumentation = new Dictionary<Type, string>
+        {
+            { typeof(Int16), "integer" },
+            { typeof(Int32), "integer" },
+            { typeof(Int64), "integer" },
+            { typeof(UInt16), "unsigned integer" },
+            { typeof(UInt32), "unsigned integer" },
+            { typeof(UInt64), "unsigned integer" },
+            { typeof(Byte), "byte" },
+            { typeof(Char), "character" },
+            { typeof(SByte), "signed byte" },
+            { typeof(Uri), "URI" },
+            { typeof(Single), "decimal number" },
+            { typeof(Double), "decimal number" },
+            { typeof(Decimal), "decimal number" },
+            { typeof(String), "string" },
+            { typeof(Guid), "globally unique identifier" },
+            { typeof(TimeSpan), "time interval" },
+            { typeof(DateTime), "date" },
+            { typeof(DateTimeOffset), "date" },
+            { typeof(Boolean), "boolean" },
+        };
+
+        private Lazy<IModelDocumentationProvider> _documentationProvider;
+
+        public ModelDescriptionGenerator(HttpConfiguration config)
+        {
+            if (config == null)
+            {
+                throw new ArgumentNullException("config");
+            }
+
+            _documentationProvider = new Lazy<IModelDocumentationProvider>(() => config.Services.GetDocumentationProvider() as IModelDocumentationProvider);
+            GeneratedModels = new Dictionary<string, ModelDescription>(StringComparer.OrdinalIgnoreCase);
+        }
+
+        public Dictionary<string, ModelDescription> GeneratedModels { get; private set; }
+
+        private IModelDocumentationProvider DocumentationProvider
+        {
+            get
+            {
+                return _documentationProvider.Value;
+            }
+        }
+
+        public ModelDescription GetOrCreateModelDescription(Type modelType)
+        {
+            if (modelType == null)
+            {
+                throw new ArgumentNullException("modelType");
+            }
+
+            Type underlyingType = Nullable.GetUnderlyingType(modelType);
+            if (underlyingType != null)
+            {
+                modelType = underlyingType;
+            }
+
+            ModelDescription modelDescription;
+            string modelName = ModelNameHelper.GetModelName(modelType);
+            if (GeneratedModels.TryGetValue(modelName, out modelDescription))
+            {
+                if (modelType != modelDescription.ModelType)
+                {
+                    throw new InvalidOperationException(
+                        String.Format(
+                            CultureInfo.CurrentCulture,
+                            "A model description could not be created. Duplicate model name '{0}' was found for types '{1}' and '{2}'. " +
+                            "Use the [ModelName] attribute to change the model name for at least one of the types so that it has a unique name.",
+                            modelName,
+                            modelDescription.ModelType.FullName,
+                            modelType.FullName));
+                }
+
+                return modelDescription;
+            }
+
+            if (DefaultTypeDocumentation.ContainsKey(modelType))
+            {
+                return GenerateSimpleTypeModelDescription(modelType);
+            }
+
+            if (modelType.IsEnum)
+            {
+                return GenerateEnumTypeModelDescription(modelType);
+            }
+
+            if (modelType.IsGenericType)
+            {
+                Type[] genericArguments = modelType.GetGenericArguments();
+
+                if (genericArguments.Length == 1)
+                {
+                    Type enumerableType = typeof(IEnumerable<>).MakeGenericType(genericArguments);
+                    if (enumerableType.IsAssignableFrom(modelType))
+                    {
+                        return GenerateCollectionModelDescription(modelType, genericArguments[0]);
+                    }
+                }
+                if (genericArguments.Length == 2)
+                {
+                    Type dictionaryType = typeof(IDictionary<,>).MakeGenericType(genericArguments);
+                    if (dictionaryType.IsAssignableFrom(modelType))
+                    {
+                        return GenerateDictionaryModelDescription(modelType, genericArguments[0], genericArguments[1]);
+                    }
+
+                    Type keyValuePairType = typeof(KeyValuePair<,>).MakeGenericType(genericArguments);
+                    if (keyValuePairType.IsAssignableFrom(modelType))
+                    {
+                        return GenerateKeyValuePairModelDescription(modelType, genericArguments[0], genericArguments[1]);
+                    }
+                }
+            }
+
+            if (modelType.IsArray)
+            {
+                Type elementType = modelType.GetElementType();
+                return GenerateCollectionModelDescription(modelType, elementType);
+            }
+
+            if (modelType == typeof(NameValueCollection))
+            {
+                return GenerateDictionaryModelDescription(modelType, typeof(string), typeof(string));
+            }
+
+            if (typeof(IDictionary).IsAssignableFrom(modelType))
+            {
+                return GenerateDictionaryModelDescription(modelType, typeof(object), typeof(object));
+            }
+
+            if (typeof(IEnumerable).IsAssignableFrom(modelType))
+            {
+                return GenerateCollectionModelDescription(modelType, typeof(object));
+            }
+
+            return GenerateComplexTypeModelDescription(modelType);
+        }
+
+        // Change this to provide different name for the member.
+        private static string GetMemberName(MemberInfo member, bool hasDataContractAttribute)
+        {
+            JsonPropertyAttribute jsonProperty = member.GetCustomAttribute<JsonPropertyAttribute>();
+            if (jsonProperty != null && !String.IsNullOrEmpty(jsonProperty.PropertyName))
+            {
+                return jsonProperty.PropertyName;
+            }
+
+            if (hasDataContractAttribute)
+            {
+                DataMemberAttribute dataMember = member.GetCustomAttribute<DataMemberAttribute>();
+                if (dataMember != null && !String.IsNullOrEmpty(dataMember.Name))
+                {
+                    return dataMember.Name;
+                }
+            }
+
+            return member.Name;
+        }
+
+        private static bool ShouldDisplayMember(MemberInfo member, bool hasDataContractAttribute)
+        {
+            JsonIgnoreAttribute jsonIgnore = member.GetCustomAttribute<JsonIgnoreAttribute>();
+            XmlIgnoreAttribute xmlIgnore = member.GetCustomAttribute<XmlIgnoreAttribute>();
+            IgnoreDataMemberAttribute ignoreDataMember = member.GetCustomAttribute<IgnoreDataMemberAttribute>();
+            NonSerializedAttribute nonSerialized = member.GetCustomAttribute<NonSerializedAttribute>();
+            ApiExplorerSettingsAttribute apiExplorerSetting = member.GetCustomAttribute<ApiExplorerSettingsAttribute>();
+
+            bool hasMemberAttribute = member.DeclaringType.IsEnum ?
+                member.GetCustomAttribute<EnumMemberAttribute>() != null :
+                member.GetCustomAttribute<DataMemberAttribute>() != null;
+
+            // Display member only if all the followings are true:
+            // no JsonIgnoreAttribute
+            // no XmlIgnoreAttribute
+            // no IgnoreDataMemberAttribute
+            // no NonSerializedAttribute
+            // no ApiExplorerSettingsAttribute with IgnoreApi set to true
+            // no DataContractAttribute without DataMemberAttribute or EnumMemberAttribute
+            return jsonIgnore == null &&
+                xmlIgnore == null &&
+                ignoreDataMember == null &&
+                nonSerialized == null &&
+                (apiExplorerSetting == null || !apiExplorerSetting.IgnoreApi) &&
+                (!hasDataContractAttribute || hasMemberAttribute);
+        }
+
+        private string CreateDefaultDocumentation(Type type)
+        {
+            string documentation;
+            if (DefaultTypeDocumentation.TryGetValue(type, out documentation))
+            {
+                return documentation;
+            }
+            if (DocumentationProvider != null)
+            {
+                documentation = DocumentationProvider.GetDocumentation(type);
+            }
+
+            return documentation;
+        }
+
+        private void GenerateAnnotations(MemberInfo property, ParameterDescription propertyModel)
+        {
+            List<ParameterAnnotation> annotations = new List<ParameterAnnotation>();
+
+            IEnumerable<Attribute> attributes = property.GetCustomAttributes();
+            foreach (Attribute attribute in attributes)
+            {
+                Func<object, string> textGenerator;
+                if (AnnotationTextGenerator.TryGetValue(attribute.GetType(), out textGenerator))
+                {
+                    annotations.Add(
+                        new ParameterAnnotation
+                        {
+                            AnnotationAttribute = attribute,
+                            Documentation = textGenerator(attribute)
+                        });
+                }
+            }
+
+            // Rearrange the annotations
+            annotations.Sort((x, y) =>
+            {
+                // Special-case RequiredAttribute so that it shows up on top
+                if (x.AnnotationAttribute is RequiredAttribute)
+                {
+                    return -1;
+                }
+                if (y.AnnotationAttribute is RequiredAttribute)
+                {
+                    return 1;
+                }
+
+                // Sort the rest based on alphabetic order of the documentation
+                return String.Compare(x.Documentation, y.Documentation, StringComparison.OrdinalIgnoreCase);
+            });
+
+            foreach (ParameterAnnotation annotation in annotations)
+            {
+                propertyModel.Annotations.Add(annotation);
+            }
+        }
+
+        private CollectionModelDescription GenerateCollectionModelDescription(Type modelType, Type elementType)
+        {
+            ModelDescription collectionModelDescription = GetOrCreateModelDescription(elementType);
+            if (collectionModelDescription != null)
+            {
+                return new CollectionModelDescription
+                {
+                    Name = ModelNameHelper.GetModelName(modelType),
+                    ModelType = modelType,
+                    ElementDescription = collectionModelDescription
+                };
+            }
+
+            return null;
+        }
+
+        private ModelDescription GenerateComplexTypeModelDescription(Type modelType)
+        {
+            ComplexTypeModelDescription complexModelDescription = new ComplexTypeModelDescription
+            {
+                Name = ModelNameHelper.GetModelName(modelType),
+                ModelType = modelType,
+                Documentation = CreateDefaultDocumentation(modelType)
+            };
+
+            GeneratedModels.Add(complexModelDescription.Name, complexModelDescription);
+            bool hasDataContractAttribute = modelType.GetCustomAttribute<DataContractAttribute>() != null;
+            PropertyInfo[] properties = modelType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
+            foreach (PropertyInfo property in properties)
+            {
+                if (ShouldDisplayMember(property, hasDataContractAttribute))
+                {
+                    ParameterDescription propertyModel = new ParameterDescription
+                    {
+                        Name = GetMemberName(property, hasDataContractAttribute)
+                    };
+
+                    if (DocumentationProvider != null)
+                    {
+                        propertyModel.Documentation = DocumentationProvider.GetDocumentation(property);
+                    }
+
+                    GenerateAnnotations(property, propertyModel);
+                    complexModelDescription.Properties.Add(propertyModel);
+                    propertyModel.TypeDescription = GetOrCreateModelDescription(property.PropertyType);
+                }
+            }
+
+            FieldInfo[] fields = modelType.GetFields(BindingFlags.Public | BindingFlags.Instance);
+            foreach (FieldInfo field in fields)
+            {
+                if (ShouldDisplayMember(field, hasDataContractAttribute))
+                {
+                    ParameterDescription propertyModel = new ParameterDescription
+                    {
+                        Name = GetMemberName(field, hasDataContractAttribute)
+                    };
+
+                    if (DocumentationProvider != null)
+                    {
+                        propertyModel.Documentation = DocumentationProvider.GetDocumentation(field);
+                    }
+
+                    complexModelDescription.Properties.Add(propertyModel);
+                    propertyModel.TypeDescription = GetOrCreateModelDescription(field.FieldType);
+                }
+            }
+
+            return complexModelDescription;
+        }
+
+        private DictionaryModelDescription GenerateDictionaryModelDescription(Type modelType, Type keyType, Type valueType)
+        {
+            ModelDescription keyModelDescription = GetOrCreateModelDescription(keyType);
+            ModelDescription valueModelDescription = GetOrCreateModelDescription(valueType);
+
+            return new DictionaryModelDescription
+            {
+                Name = ModelNameHelper.GetModelName(modelType),
+                ModelType = modelType,
+                KeyModelDescription = keyModelDescription,
+                ValueModelDescription = valueModelDescription
+            };
+        }
+
+        private EnumTypeModelDescription GenerateEnumTypeModelDescription(Type modelType)
+        {
+            EnumTypeModelDescription enumDescription = new EnumTypeModelDescription
+            {
+                Name = ModelNameHelper.GetModelName(modelType),
+                ModelType = modelType,
+                Documentation = CreateDefaultDocumentation(modelType)
+            };
+            bool hasDataContractAttribute = modelType.GetCustomAttribute<DataContractAttribute>() != null;
+            foreach (FieldInfo field in modelType.GetFields(BindingFlags.Public | BindingFlags.Static))
+            {
+                if (ShouldDisplayMember(field, hasDataContractAttribute))
+                {
+                    EnumValueDescription enumValue = new EnumValueDescription
+                    {
+                        Name = field.Name,
+                        Value = field.GetRawConstantValue().ToString()
+                    };
+                    if (DocumentationProvider != null)
+                    {
+                        enumValue.Documentation = DocumentationProvider.GetDocumentation(field);
+                    }
+                    enumDescription.Values.Add(enumValue);
+                }
+            }
+            GeneratedModels.Add(enumDescription.Name, enumDescription);
+
+            return enumDescription;
+        }
+
+        private KeyValuePairModelDescription GenerateKeyValuePairModelDescription(Type modelType, Type keyType, Type valueType)
+        {
+            ModelDescription keyModelDescription = GetOrCreateModelDescription(keyType);
+            ModelDescription valueModelDescription = GetOrCreateModelDescription(valueType);
+
+            return new KeyValuePairModelDescription
+            {
+                Name = ModelNameHelper.GetModelName(modelType),
+                ModelType = modelType,
+                KeyModelDescription = keyModelDescription,
+                ValueModelDescription = valueModelDescription
+            };
+        }
+
+        private ModelDescription GenerateSimpleTypeModelDescription(Type modelType)
+        {
+            SimpleTypeModelDescription simpleModelDescription = new SimpleTypeModelDescription
+            {
+                Name = ModelNameHelper.GetModelName(modelType),
+                ModelType = modelType,
+                Documentation = CreateDefaultDocumentation(modelType)
+            };
+            GeneratedModels.Add(simpleModelDescription.Name, simpleModelDescription);
+
+            return simpleModelDescription;
+        }
+    }
+}

+ 18 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/ModelNameAttribute.cs

@@ -0,0 +1,18 @@
+using System;
+
+namespace VsdConverter.Areas.HelpPage.ModelDescriptions
+{
+    /// <summary>
+    /// Use this attribute to change the name of the <see cref="ModelDescription"/> generated for a type.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum, AllowMultiple = false, Inherited = false)]
+    public sealed class ModelNameAttribute : Attribute
+    {
+        public ModelNameAttribute(string name)
+        {
+            Name = name;
+        }
+
+        public string Name { get; private set; }
+    }
+}

+ 36 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/ModelNameHelper.cs

@@ -0,0 +1,36 @@
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+
+namespace VsdConverter.Areas.HelpPage.ModelDescriptions
+{
+    internal static class ModelNameHelper
+    {
+        // Modify this to provide custom model name mapping.
+        public static string GetModelName(Type type)
+        {
+            ModelNameAttribute modelNameAttribute = type.GetCustomAttribute<ModelNameAttribute>();
+            if (modelNameAttribute != null && !String.IsNullOrEmpty(modelNameAttribute.Name))
+            {
+                return modelNameAttribute.Name;
+            }
+
+            string modelName = type.Name;
+            if (type.IsGenericType)
+            {
+                // Format the generic type name to something like: GenericOfAgurment1AndArgument2
+                Type genericType = type.GetGenericTypeDefinition();
+                Type[] genericArguments = type.GetGenericArguments();
+                string genericTypeName = genericType.Name;
+
+                // Trim the generic parameter counts from the name
+                genericTypeName = genericTypeName.Substring(0, genericTypeName.IndexOf('`'));
+                string[] argumentTypeNames = genericArguments.Select(t => GetModelName(t)).ToArray();
+                modelName = String.Format(CultureInfo.InvariantCulture, "{0}Of{1}", genericTypeName, String.Join("And", argumentTypeNames));
+            }
+
+            return modelName;
+        }
+    }
+}

+ 11 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/ParameterAnnotation.cs

@@ -0,0 +1,11 @@
+using System;
+
+namespace VsdConverter.Areas.HelpPage.ModelDescriptions
+{
+    public class ParameterAnnotation
+    {
+        public Attribute AnnotationAttribute { get; set; }
+
+        public string Documentation { get; set; }
+    }
+}

+ 21 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/ParameterDescription.cs

@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+namespace VsdConverter.Areas.HelpPage.ModelDescriptions
+{
+    public class ParameterDescription
+    {
+        public ParameterDescription()
+        {
+            Annotations = new Collection<ParameterAnnotation>();
+        }
+
+        public Collection<ParameterAnnotation> Annotations { get; private set; }
+
+        public string Documentation { get; set; }
+
+        public string Name { get; set; }
+
+        public ModelDescription TypeDescription { get; set; }
+    }
+}

+ 6 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/ModelDescriptions/SimpleTypeModelDescription.cs

@@ -0,0 +1,6 @@
+namespace VsdConverter.Areas.HelpPage.ModelDescriptions
+{
+    public class SimpleTypeModelDescription : ModelDescription
+    {
+    }
+}

+ 108 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Models/HelpPageApiModel.cs

@@ -0,0 +1,108 @@
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Net.Http.Headers;
+using System.Web.Http.Description;
+using VsdConverter.Areas.HelpPage.ModelDescriptions;
+
+namespace VsdConverter.Areas.HelpPage.Models
+{
+    /// <summary>
+    /// The model that represents an API displayed on the help page.
+    /// </summary>
+    public class HelpPageApiModel
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="HelpPageApiModel"/> class.
+        /// </summary>
+        public HelpPageApiModel()
+        {
+            UriParameters = new Collection<ParameterDescription>();
+            SampleRequests = new Dictionary<MediaTypeHeaderValue, object>();
+            SampleResponses = new Dictionary<MediaTypeHeaderValue, object>();
+            ErrorMessages = new Collection<string>();
+        }
+
+        /// <summary>
+        /// Gets or sets the <see cref="ApiDescription"/> that describes the API.
+        /// </summary>
+        public ApiDescription ApiDescription { get; set; }
+
+        /// <summary>
+        /// Gets or sets the <see cref="ParameterDescription"/> collection that describes the URI parameters for the API.
+        /// </summary>
+        public Collection<ParameterDescription> UriParameters { get; private set; }
+
+        /// <summary>
+        /// Gets or sets the documentation for the request.
+        /// </summary>
+        public string RequestDocumentation { get; set; }
+
+        /// <summary>
+        /// Gets or sets the <see cref="ModelDescription"/> that describes the request body.
+        /// </summary>
+        public ModelDescription RequestModelDescription { get; set; }
+
+        /// <summary>
+        /// Gets the request body parameter descriptions.
+        /// </summary>
+        public IList<ParameterDescription> RequestBodyParameters
+        {
+            get
+            {
+                return GetParameterDescriptions(RequestModelDescription);
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the <see cref="ModelDescription"/> that describes the resource.
+        /// </summary>
+        public ModelDescription ResourceDescription { get; set; }
+
+        /// <summary>
+        /// Gets the resource property descriptions.
+        /// </summary>
+        public IList<ParameterDescription> ResourceProperties
+        {
+            get
+            {
+                return GetParameterDescriptions(ResourceDescription);
+            }
+        }
+
+        /// <summary>
+        /// Gets the sample requests associated with the API.
+        /// </summary>
+        public IDictionary<MediaTypeHeaderValue, object> SampleRequests { get; private set; }
+
+        /// <summary>
+        /// Gets the sample responses associated with the API.
+        /// </summary>
+        public IDictionary<MediaTypeHeaderValue, object> SampleResponses { get; private set; }
+
+        /// <summary>
+        /// Gets the error messages associated with this model.
+        /// </summary>
+        public Collection<string> ErrorMessages { get; private set; }
+
+        private static IList<ParameterDescription> GetParameterDescriptions(ModelDescription modelDescription)
+        {
+            ComplexTypeModelDescription complexTypeModelDescription = modelDescription as ComplexTypeModelDescription;
+            if (complexTypeModelDescription != null)
+            {
+                return complexTypeModelDescription.Properties;
+            }
+
+            CollectionModelDescription collectionModelDescription = modelDescription as CollectionModelDescription;
+            if (collectionModelDescription != null)
+            {
+                complexTypeModelDescription = collectionModelDescription.ElementDescription as ComplexTypeModelDescription;
+                if (complexTypeModelDescription != null)
+                {
+                    return complexTypeModelDescription.Properties;
+                }
+            }
+
+            return null;
+        }
+    }
+}

+ 444 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/SampleGeneration/HelpPageSampleGenerator.cs

@@ -0,0 +1,444 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Formatting;
+using System.Net.Http.Headers;
+using System.Web.Http.Description;
+using System.Xml.Linq;
+using Newtonsoft.Json;
+
+namespace VsdConverter.Areas.HelpPage
+{
+    /// <summary>
+    /// This class will generate the samples for the help page.
+    /// </summary>
+    public class HelpPageSampleGenerator
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="HelpPageSampleGenerator"/> class.
+        /// </summary>
+        public HelpPageSampleGenerator()
+        {
+            ActualHttpMessageTypes = new Dictionary<HelpPageSampleKey, Type>();
+            ActionSamples = new Dictionary<HelpPageSampleKey, object>();
+            SampleObjects = new Dictionary<Type, object>();
+            SampleObjectFactories = new List<Func<HelpPageSampleGenerator, Type, object>>
+            {
+                DefaultSampleObjectFactory,
+            };
+        }
+
+        /// <summary>
+        /// Gets CLR types that are used as the content of <see cref="HttpRequestMessage"/> or <see cref="HttpResponseMessage"/>.
+        /// </summary>
+        public IDictionary<HelpPageSampleKey, Type> ActualHttpMessageTypes { get; internal set; }
+
+        /// <summary>
+        /// Gets the objects that are used directly as samples for certain actions.
+        /// </summary>
+        public IDictionary<HelpPageSampleKey, object> ActionSamples { get; internal set; }
+
+        /// <summary>
+        /// Gets the objects that are serialized as samples by the supported formatters.
+        /// </summary>
+        public IDictionary<Type, object> SampleObjects { get; internal set; }
+
+        /// <summary>
+        /// Gets factories for the objects that the supported formatters will serialize as samples. Processed in order,
+        /// stopping when the factory successfully returns a non-<see langref="null"/> object.
+        /// </summary>
+        /// <remarks>
+        /// Collection includes just <see cref="ObjectGenerator.GenerateObject(Type)"/> initially. Use
+        /// <code>SampleObjectFactories.Insert(0, func)</code> to provide an override and
+        /// <code>SampleObjectFactories.Add(func)</code> to provide a fallback.</remarks>
+        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures",
+            Justification = "This is an appropriate nesting of generic types")]
+        public IList<Func<HelpPageSampleGenerator, Type, object>> SampleObjectFactories { get; private set; }
+
+        /// <summary>
+        /// Gets the request body samples for a given <see cref="ApiDescription"/>.
+        /// </summary>
+        /// <param name="api">The <see cref="ApiDescription"/>.</param>
+        /// <returns>The samples keyed by media type.</returns>
+        public IDictionary<MediaTypeHeaderValue, object> GetSampleRequests(ApiDescription api)
+        {
+            return GetSample(api, SampleDirection.Request);
+        }
+
+        /// <summary>
+        /// Gets the response body samples for a given <see cref="ApiDescription"/>.
+        /// </summary>
+        /// <param name="api">The <see cref="ApiDescription"/>.</param>
+        /// <returns>The samples keyed by media type.</returns>
+        public IDictionary<MediaTypeHeaderValue, object> GetSampleResponses(ApiDescription api)
+        {
+            return GetSample(api, SampleDirection.Response);
+        }
+
+        /// <summary>
+        /// Gets the request or response body samples.
+        /// </summary>
+        /// <param name="api">The <see cref="ApiDescription"/>.</param>
+        /// <param name="sampleDirection">The value indicating whether the sample is for a request or for a response.</param>
+        /// <returns>The samples keyed by media type.</returns>
+        public virtual IDictionary<MediaTypeHeaderValue, object> GetSample(ApiDescription api, SampleDirection sampleDirection)
+        {
+            if (api == null)
+            {
+                throw new ArgumentNullException("api");
+            }
+            string controllerName = api.ActionDescriptor.ControllerDescriptor.ControllerName;
+            string actionName = api.ActionDescriptor.ActionName;
+            IEnumerable<string> parameterNames = api.ParameterDescriptions.Select(p => p.Name);
+            Collection<MediaTypeFormatter> formatters;
+            Type type = ResolveType(api, controllerName, actionName, parameterNames, sampleDirection, out formatters);
+            var samples = new Dictionary<MediaTypeHeaderValue, object>();
+
+            // Use the samples provided directly for actions
+            var actionSamples = GetAllActionSamples(controllerName, actionName, parameterNames, sampleDirection);
+            foreach (var actionSample in actionSamples)
+            {
+                samples.Add(actionSample.Key.MediaType, WrapSampleIfString(actionSample.Value));
+            }
+
+            // Do the sample generation based on formatters only if an action doesn't return an HttpResponseMessage.
+            // Here we cannot rely on formatters because we don't know what's in the HttpResponseMessage, it might not even use formatters.
+            if (type != null && !typeof(HttpResponseMessage).IsAssignableFrom(type))
+            {
+                object sampleObject = GetSampleObject(type);
+                foreach (var formatter in formatters)
+                {
+                    foreach (MediaTypeHeaderValue mediaType in formatter.SupportedMediaTypes)
+                    {
+                        if (!samples.ContainsKey(mediaType))
+                        {
+                            object sample = GetActionSample(controllerName, actionName, parameterNames, type, formatter, mediaType, sampleDirection);
+
+                            // If no sample found, try generate sample using formatter and sample object
+                            if (sample == null && sampleObject != null)
+                            {
+                                sample = WriteSampleObjectUsingFormatter(formatter, sampleObject, type, mediaType);
+                            }
+
+                            samples.Add(mediaType, WrapSampleIfString(sample));
+                        }
+                    }
+                }
+            }
+
+            return samples;
+        }
+
+        /// <summary>
+        /// Search for samples that are provided directly through <see cref="ActionSamples"/>.
+        /// </summary>
+        /// <param name="controllerName">Name of the controller.</param>
+        /// <param name="actionName">Name of the action.</param>
+        /// <param name="parameterNames">The parameter names.</param>
+        /// <param name="type">The CLR type.</param>
+        /// <param name="formatter">The formatter.</param>
+        /// <param name="mediaType">The media type.</param>
+        /// <param name="sampleDirection">The value indicating whether the sample is for a request or for a response.</param>
+        /// <returns>The sample that matches the parameters.</returns>
+        public virtual object GetActionSample(string controllerName, string actionName, IEnumerable<string> parameterNames, Type type, MediaTypeFormatter formatter, MediaTypeHeaderValue mediaType, SampleDirection sampleDirection)
+        {
+            object sample;
+
+            // First, try to get the sample provided for the specified mediaType, sampleDirection, controllerName, actionName and parameterNames.
+            // If not found, try to get the sample provided for the specified mediaType, sampleDirection, controllerName and actionName regardless of the parameterNames.
+            // If still not found, try to get the sample provided for the specified mediaType and type.
+            // Finally, try to get the sample provided for the specified mediaType.
+            if (ActionSamples.TryGetValue(new HelpPageSampleKey(mediaType, sampleDirection, controllerName, actionName, parameterNames), out sample) ||
+                ActionSamples.TryGetValue(new HelpPageSampleKey(mediaType, sampleDirection, controllerName, actionName, new[] { "*" }), out sample) ||
+                ActionSamples.TryGetValue(new HelpPageSampleKey(mediaType, type), out sample) ||
+                ActionSamples.TryGetValue(new HelpPageSampleKey(mediaType), out sample))
+            {
+                return sample;
+            }
+
+            return null;
+        }
+
+        /// <summary>
+        /// Gets the sample object that will be serialized by the formatters. 
+        /// First, it will look at the <see cref="SampleObjects"/>. If no sample object is found, it will try to create
+        /// one using <see cref="DefaultSampleObjectFactory"/> (which wraps an <see cref="ObjectGenerator"/>) and other
+        /// factories in <see cref="SampleObjectFactories"/>.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <returns>The sample object.</returns>
+        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
+            Justification = "Even if all items in SampleObjectFactories throw, problem will be visible as missing sample.")]
+        public virtual object GetSampleObject(Type type)
+        {
+            object sampleObject;
+
+            if (!SampleObjects.TryGetValue(type, out sampleObject))
+            {
+                // No specific object available, try our factories.
+                foreach (Func<HelpPageSampleGenerator, Type, object> factory in SampleObjectFactories)
+                {
+                    if (factory == null)
+                    {
+                        continue;
+                    }
+
+                    try
+                    {
+                        sampleObject = factory(this, type);
+                        if (sampleObject != null)
+                        {
+                            break;
+                        }
+                    }
+                    catch
+                    {
+                        // Ignore any problems encountered in the factory; go on to the next one (if any).
+                    }
+                }
+            }
+
+            return sampleObject;
+        }
+
+        /// <summary>
+        /// Resolves the actual type of <see cref="System.Net.Http.ObjectContent{T}"/> passed to the <see cref="System.Net.Http.HttpRequestMessage"/> in an action.
+        /// </summary>
+        /// <param name="api">The <see cref="ApiDescription"/>.</param>
+        /// <returns>The type.</returns>
+        public virtual Type ResolveHttpRequestMessageType(ApiDescription api)
+        {
+            string controllerName = api.ActionDescriptor.ControllerDescriptor.ControllerName;
+            string actionName = api.ActionDescriptor.ActionName;
+            IEnumerable<string> parameterNames = api.ParameterDescriptions.Select(p => p.Name);
+            Collection<MediaTypeFormatter> formatters;
+            return ResolveType(api, controllerName, actionName, parameterNames, SampleDirection.Request, out formatters);
+        }
+
+        /// <summary>
+        /// Resolves the type of the action parameter or return value when <see cref="HttpRequestMessage"/> or <see cref="HttpResponseMessage"/> is used.
+        /// </summary>
+        /// <param name="api">The <see cref="ApiDescription"/>.</param>
+        /// <param name="controllerName">Name of the controller.</param>
+        /// <param name="actionName">Name of the action.</param>
+        /// <param name="parameterNames">The parameter names.</param>
+        /// <param name="sampleDirection">The value indicating whether the sample is for a request or a response.</param>
+        /// <param name="formatters">The formatters.</param>
+        [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", Justification = "This is only used in advanced scenarios.")]
+        public virtual Type ResolveType(ApiDescription api, string controllerName, string actionName, IEnumerable<string> parameterNames, SampleDirection sampleDirection, out Collection<MediaTypeFormatter> formatters)
+        {
+            if (!Enum.IsDefined(typeof(SampleDirection), sampleDirection))
+            {
+                throw new InvalidEnumArgumentException("sampleDirection", (int)sampleDirection, typeof(SampleDirection));
+            }
+            if (api == null)
+            {
+                throw new ArgumentNullException("api");
+            }
+            Type type;
+            if (ActualHttpMessageTypes.TryGetValue(new HelpPageSampleKey(sampleDirection, controllerName, actionName, parameterNames), out type) ||
+                ActualHttpMessageTypes.TryGetValue(new HelpPageSampleKey(sampleDirection, controllerName, actionName, new[] { "*" }), out type))
+            {
+                // Re-compute the supported formatters based on type
+                Collection<MediaTypeFormatter> newFormatters = new Collection<MediaTypeFormatter>();
+                foreach (var formatter in api.ActionDescriptor.Configuration.Formatters)
+                {
+                    if (IsFormatSupported(sampleDirection, formatter, type))
+                    {
+                        newFormatters.Add(formatter);
+                    }
+                }
+                formatters = newFormatters;
+            }
+            else
+            {
+                switch (sampleDirection)
+                {
+                    case SampleDirection.Request:
+                        ApiParameterDescription requestBodyParameter = api.ParameterDescriptions.FirstOrDefault(p => p.Source == ApiParameterSource.FromBody);
+                        type = requestBodyParameter == null ? null : requestBodyParameter.ParameterDescriptor.ParameterType;
+                        formatters = api.SupportedRequestBodyFormatters;
+                        break;
+                    case SampleDirection.Response:
+                    default:
+                        type = api.ResponseDescription.ResponseType ?? api.ResponseDescription.DeclaredType;
+                        formatters = api.SupportedResponseFormatters;
+                        break;
+                }
+            }
+
+            return type;
+        }
+
+        /// <summary>
+        /// Writes the sample object using formatter.
+        /// </summary>
+        /// <param name="formatter">The formatter.</param>
+        /// <param name="value">The value.</param>
+        /// <param name="type">The type.</param>
+        /// <param name="mediaType">Type of the media.</param>
+        /// <returns></returns>
+        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "The exception is recorded as InvalidSample.")]
+        public virtual object WriteSampleObjectUsingFormatter(MediaTypeFormatter formatter, object value, Type type, MediaTypeHeaderValue mediaType)
+        {
+            if (formatter == null)
+            {
+                throw new ArgumentNullException("formatter");
+            }
+            if (mediaType == null)
+            {
+                throw new ArgumentNullException("mediaType");
+            }
+
+            object sample = String.Empty;
+            MemoryStream ms = null;
+            HttpContent content = null;
+            try
+            {
+                if (formatter.CanWriteType(type))
+                {
+                    ms = new MemoryStream();
+                    content = new ObjectContent(type, value, formatter, mediaType);
+                    formatter.WriteToStreamAsync(type, value, ms, content, null).Wait();
+                    ms.Position = 0;
+                    StreamReader reader = new StreamReader(ms);
+                    string serializedSampleString = reader.ReadToEnd();
+                    if (mediaType.MediaType.ToUpperInvariant().Contains("XML"))
+                    {
+                        serializedSampleString = TryFormatXml(serializedSampleString);
+                    }
+                    else if (mediaType.MediaType.ToUpperInvariant().Contains("JSON"))
+                    {
+                        serializedSampleString = TryFormatJson(serializedSampleString);
+                    }
+
+                    sample = new TextSample(serializedSampleString);
+                }
+                else
+                {
+                    sample = new InvalidSample(String.Format(
+                        CultureInfo.CurrentCulture,
+                        "Failed to generate the sample for media type '{0}'. Cannot use formatter '{1}' to write type '{2}'.",
+                        mediaType,
+                        formatter.GetType().Name,
+                        type.Name));
+                }
+            }
+            catch (Exception e)
+            {
+                sample = new InvalidSample(String.Format(
+                    CultureInfo.CurrentCulture,
+                    "An exception has occurred while using the formatter '{0}' to generate sample for media type '{1}'. Exception message: {2}",
+                    formatter.GetType().Name,
+                    mediaType.MediaType,
+                    UnwrapException(e).Message));
+            }
+            finally
+            {
+                if (ms != null)
+                {
+                    ms.Dispose();
+                }
+                if (content != null)
+                {
+                    content.Dispose();
+                }
+            }
+
+            return sample;
+        }
+
+        internal static Exception UnwrapException(Exception exception)
+        {
+            AggregateException aggregateException = exception as AggregateException;
+            if (aggregateException != null)
+            {
+                return aggregateException.Flatten().InnerException;
+            }
+            return exception;
+        }
+
+        // Default factory for sample objects
+        private static object DefaultSampleObjectFactory(HelpPageSampleGenerator sampleGenerator, Type type)
+        {
+            // Try to create a default sample object
+            ObjectGenerator objectGenerator = new ObjectGenerator();
+            return objectGenerator.GenerateObject(type);
+        }
+
+        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Handling the failure by returning the original string.")]
+        private static string TryFormatJson(string str)
+        {
+            try
+            {
+                object parsedJson = JsonConvert.DeserializeObject(str);
+                return JsonConvert.SerializeObject(parsedJson, Formatting.Indented);
+            }
+            catch
+            {
+                // can't parse JSON, return the original string
+                return str;
+            }
+        }
+
+        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Handling the failure by returning the original string.")]
+        private static string TryFormatXml(string str)
+        {
+            try
+            {
+                XDocument xml = XDocument.Parse(str);
+                return xml.ToString();
+            }
+            catch
+            {
+                // can't parse XML, return the original string
+                return str;
+            }
+        }
+
+        private static bool IsFormatSupported(SampleDirection sampleDirection, MediaTypeFormatter formatter, Type type)
+        {
+            switch (sampleDirection)
+            {
+                case SampleDirection.Request:
+                    return formatter.CanReadType(type);
+                case SampleDirection.Response:
+                    return formatter.CanWriteType(type);
+            }
+            return false;
+        }
+
+        private IEnumerable<KeyValuePair<HelpPageSampleKey, object>> GetAllActionSamples(string controllerName, string actionName, IEnumerable<string> parameterNames, SampleDirection sampleDirection)
+        {
+            HashSet<string> parameterNamesSet = new HashSet<string>(parameterNames, StringComparer.OrdinalIgnoreCase);
+            foreach (var sample in ActionSamples)
+            {
+                HelpPageSampleKey sampleKey = sample.Key;
+                if (String.Equals(controllerName, sampleKey.ControllerName, StringComparison.OrdinalIgnoreCase) &&
+                    String.Equals(actionName, sampleKey.ActionName, StringComparison.OrdinalIgnoreCase) &&
+                    (sampleKey.ParameterNames.SetEquals(new[] { "*" }) || parameterNamesSet.SetEquals(sampleKey.ParameterNames)) &&
+                    sampleDirection == sampleKey.SampleDirection)
+                {
+                    yield return sample;
+                }
+            }
+        }
+
+        private static object WrapSampleIfString(object sample)
+        {
+            string stringSample = sample as string;
+            if (stringSample != null)
+            {
+                return new TextSample(stringSample);
+            }
+
+            return sample;
+        }
+    }
+}

+ 172 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/SampleGeneration/HelpPageSampleKey.cs

@@ -0,0 +1,172 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Net.Http.Headers;
+
+namespace VsdConverter.Areas.HelpPage
+{
+    /// <summary>
+    /// This is used to identify the place where the sample should be applied.
+    /// </summary>
+    public class HelpPageSampleKey
+    {
+        /// <summary>
+        /// Creates a new <see cref="HelpPageSampleKey"/> based on media type.
+        /// </summary>
+        /// <param name="mediaType">The media type.</param>
+        public HelpPageSampleKey(MediaTypeHeaderValue mediaType)
+        {
+            if (mediaType == null)
+            {
+                throw new ArgumentNullException("mediaType");
+            }
+
+            ActionName = String.Empty;
+            ControllerName = String.Empty;
+            MediaType = mediaType;
+            ParameterNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
+        }
+
+        /// <summary>
+        /// Creates a new <see cref="HelpPageSampleKey"/> based on media type and CLR type.
+        /// </summary>
+        /// <param name="mediaType">The media type.</param>
+        /// <param name="type">The CLR type.</param>
+        public HelpPageSampleKey(MediaTypeHeaderValue mediaType, Type type)
+            : this(mediaType)
+        {
+            if (type == null)
+            {
+                throw new ArgumentNullException("type");
+            }
+
+            ParameterType = type;
+        }
+
+        /// <summary>
+        /// Creates a new <see cref="HelpPageSampleKey"/> based on <see cref="SampleDirection"/>, controller name, action name and parameter names.
+        /// </summary>
+        /// <param name="sampleDirection">The <see cref="SampleDirection"/>.</param>
+        /// <param name="controllerName">Name of the controller.</param>
+        /// <param name="actionName">Name of the action.</param>
+        /// <param name="parameterNames">The parameter names.</param>
+        public HelpPageSampleKey(SampleDirection sampleDirection, string controllerName, string actionName, IEnumerable<string> parameterNames)
+        {
+            if (!Enum.IsDefined(typeof(SampleDirection), sampleDirection))
+            {
+                throw new InvalidEnumArgumentException("sampleDirection", (int)sampleDirection, typeof(SampleDirection));
+            }
+            if (controllerName == null)
+            {
+                throw new ArgumentNullException("controllerName");
+            }
+            if (actionName == null)
+            {
+                throw new ArgumentNullException("actionName");
+            }
+            if (parameterNames == null)
+            {
+                throw new ArgumentNullException("parameterNames");
+            }
+
+            ControllerName = controllerName;
+            ActionName = actionName;
+            ParameterNames = new HashSet<string>(parameterNames, StringComparer.OrdinalIgnoreCase);
+            SampleDirection = sampleDirection;
+        }
+
+        /// <summary>
+        /// Creates a new <see cref="HelpPageSampleKey"/> based on media type, <see cref="SampleDirection"/>, controller name, action name and parameter names.
+        /// </summary>
+        /// <param name="mediaType">The media type.</param>
+        /// <param name="sampleDirection">The <see cref="SampleDirection"/>.</param>
+        /// <param name="controllerName">Name of the controller.</param>
+        /// <param name="actionName">Name of the action.</param>
+        /// <param name="parameterNames">The parameter names.</param>
+        public HelpPageSampleKey(MediaTypeHeaderValue mediaType, SampleDirection sampleDirection, string controllerName, string actionName, IEnumerable<string> parameterNames)
+            : this(sampleDirection, controllerName, actionName, parameterNames)
+        {
+            if (mediaType == null)
+            {
+                throw new ArgumentNullException("mediaType");
+            }
+
+            MediaType = mediaType;
+        }
+
+        /// <summary>
+        /// Gets the name of the controller.
+        /// </summary>
+        /// <value>
+        /// The name of the controller.
+        /// </value>
+        public string ControllerName { get; private set; }
+
+        /// <summary>
+        /// Gets the name of the action.
+        /// </summary>
+        /// <value>
+        /// The name of the action.
+        /// </value>
+        public string ActionName { get; private set; }
+
+        /// <summary>
+        /// Gets the media type.
+        /// </summary>
+        /// <value>
+        /// The media type.
+        /// </value>
+        public MediaTypeHeaderValue MediaType { get; private set; }
+
+        /// <summary>
+        /// Gets the parameter names.
+        /// </summary>
+        public HashSet<string> ParameterNames { get; private set; }
+
+        public Type ParameterType { get; private set; }
+
+        /// <summary>
+        /// Gets the <see cref="SampleDirection"/>.
+        /// </summary>
+        public SampleDirection? SampleDirection { get; private set; }
+
+        public override bool Equals(object obj)
+        {
+            HelpPageSampleKey otherKey = obj as HelpPageSampleKey;
+            if (otherKey == null)
+            {
+                return false;
+            }
+
+            return String.Equals(ControllerName, otherKey.ControllerName, StringComparison.OrdinalIgnoreCase) &&
+                String.Equals(ActionName, otherKey.ActionName, StringComparison.OrdinalIgnoreCase) &&
+                (MediaType == otherKey.MediaType || (MediaType != null && MediaType.Equals(otherKey.MediaType))) &&
+                ParameterType == otherKey.ParameterType &&
+                SampleDirection == otherKey.SampleDirection &&
+                ParameterNames.SetEquals(otherKey.ParameterNames);
+        }
+
+        public override int GetHashCode()
+        {
+            int hashCode = ControllerName.ToUpperInvariant().GetHashCode() ^ ActionName.ToUpperInvariant().GetHashCode();
+            if (MediaType != null)
+            {
+                hashCode ^= MediaType.GetHashCode();
+            }
+            if (SampleDirection != null)
+            {
+                hashCode ^= SampleDirection.GetHashCode();
+            }
+            if (ParameterType != null)
+            {
+                hashCode ^= ParameterType.GetHashCode();
+            }
+            foreach (string parameterName in ParameterNames)
+            {
+                hashCode ^= parameterName.ToUpperInvariant().GetHashCode();
+            }
+
+            return hashCode;
+        }
+    }
+}

+ 41 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/SampleGeneration/ImageSample.cs

@@ -0,0 +1,41 @@
+using System;
+
+namespace VsdConverter.Areas.HelpPage
+{
+    /// <summary>
+    /// This represents an image sample on the help page. There's a display template named ImageSample associated with this class.
+    /// </summary>
+    public class ImageSample
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ImageSample"/> class.
+        /// </summary>
+        /// <param name="src">The URL of an image.</param>
+        public ImageSample(string src)
+        {
+            if (src == null)
+            {
+                throw new ArgumentNullException("src");
+            }
+            Src = src;
+        }
+
+        public string Src { get; private set; }
+
+        public override bool Equals(object obj)
+        {
+            ImageSample other = obj as ImageSample;
+            return other != null && Src == other.Src;
+        }
+
+        public override int GetHashCode()
+        {
+            return Src.GetHashCode();
+        }
+
+        public override string ToString()
+        {
+            return Src;
+        }
+    }
+}

+ 37 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/SampleGeneration/InvalidSample.cs

@@ -0,0 +1,37 @@
+using System;
+
+namespace VsdConverter.Areas.HelpPage
+{
+    /// <summary>
+    /// This represents an invalid sample on the help page. There's a display template named InvalidSample associated with this class.
+    /// </summary>
+    public class InvalidSample
+    {
+        public InvalidSample(string errorMessage)
+        {
+            if (errorMessage == null)
+            {
+                throw new ArgumentNullException("errorMessage");
+            }
+            ErrorMessage = errorMessage;
+        }
+
+        public string ErrorMessage { get; private set; }
+
+        public override bool Equals(object obj)
+        {
+            InvalidSample other = obj as InvalidSample;
+            return other != null && ErrorMessage == other.ErrorMessage;
+        }
+
+        public override int GetHashCode()
+        {
+            return ErrorMessage.GetHashCode();
+        }
+
+        public override string ToString()
+        {
+            return ErrorMessage;
+        }
+    }
+}

+ 456 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/SampleGeneration/ObjectGenerator.cs

@@ -0,0 +1,456 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+
+namespace VsdConverter.Areas.HelpPage
+{
+    /// <summary>
+    /// This class will create an object of a given type and populate it with sample data.
+    /// </summary>
+    public class ObjectGenerator
+    {
+        internal const int DefaultCollectionSize = 2;
+        private readonly SimpleTypeObjectGenerator SimpleObjectGenerator = new SimpleTypeObjectGenerator();
+
+        /// <summary>
+        /// Generates an object for a given type. The type needs to be public, have a public default constructor and settable public properties/fields. Currently it supports the following types:
+        /// Simple types: <see cref="int"/>, <see cref="string"/>, <see cref="Enum"/>, <see cref="DateTime"/>, <see cref="Uri"/>, etc.
+        /// Complex types: POCO types.
+        /// Nullables: <see cref="Nullable{T}"/>.
+        /// Arrays: arrays of simple types or complex types.
+        /// Key value pairs: <see cref="KeyValuePair{TKey,TValue}"/>
+        /// Tuples: <see cref="Tuple{T1}"/>, <see cref="Tuple{T1,T2}"/>, etc
+        /// Dictionaries: <see cref="IDictionary{TKey,TValue}"/> or anything deriving from <see cref="IDictionary{TKey,TValue}"/>.
+        /// Collections: <see cref="IList{T}"/>, <see cref="IEnumerable{T}"/>, <see cref="ICollection{T}"/>, <see cref="IList"/>, <see cref="IEnumerable"/>, <see cref="ICollection"/> or anything deriving from <see cref="ICollection{T}"/> or <see cref="IList"/>.
+        /// Queryables: <see cref="IQueryable"/>, <see cref="IQueryable{T}"/>.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <returns>An object of the given type.</returns>
+        public object GenerateObject(Type type)
+        {
+            return GenerateObject(type, new Dictionary<Type, object>());
+        }
+
+        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Here we just want to return null if anything goes wrong.")]
+        private object GenerateObject(Type type, Dictionary<Type, object> createdObjectReferences)
+        {
+            try
+            {
+                if (SimpleTypeObjectGenerator.CanGenerateObject(type))
+                {
+                    return SimpleObjectGenerator.GenerateObject(type);
+                }
+
+                if (type.IsArray)
+                {
+                    return GenerateArray(type, DefaultCollectionSize, createdObjectReferences);
+                }
+
+                if (type.IsGenericType)
+                {
+                    return GenerateGenericType(type, DefaultCollectionSize, createdObjectReferences);
+                }
+
+                if (type == typeof(IDictionary))
+                {
+                    return GenerateDictionary(typeof(Hashtable), DefaultCollectionSize, createdObjectReferences);
+                }
+
+                if (typeof(IDictionary).IsAssignableFrom(type))
+                {
+                    return GenerateDictionary(type, DefaultCollectionSize, createdObjectReferences);
+                }
+
+                if (type == typeof(IList) ||
+                    type == typeof(IEnumerable) ||
+                    type == typeof(ICollection))
+                {
+                    return GenerateCollection(typeof(ArrayList), DefaultCollectionSize, createdObjectReferences);
+                }
+
+                if (typeof(IList).IsAssignableFrom(type))
+                {
+                    return GenerateCollection(type, DefaultCollectionSize, createdObjectReferences);
+                }
+
+                if (type == typeof(IQueryable))
+                {
+                    return GenerateQueryable(type, DefaultCollectionSize, createdObjectReferences);
+                }
+
+                if (type.IsEnum)
+                {
+                    return GenerateEnum(type);
+                }
+
+                if (type.IsPublic || type.IsNestedPublic)
+                {
+                    return GenerateComplexObject(type, createdObjectReferences);
+                }
+            }
+            catch
+            {
+                // Returns null if anything fails
+                return null;
+            }
+
+            return null;
+        }
+
+        private static object GenerateGenericType(Type type, int collectionSize, Dictionary<Type, object> createdObjectReferences)
+        {
+            Type genericTypeDefinition = type.GetGenericTypeDefinition();
+            if (genericTypeDefinition == typeof(Nullable<>))
+            {
+                return GenerateNullable(type, createdObjectReferences);
+            }
+
+            if (genericTypeDefinition == typeof(KeyValuePair<,>))
+            {
+                return GenerateKeyValuePair(type, createdObjectReferences);
+            }
+
+            if (IsTuple(genericTypeDefinition))
+            {
+                return GenerateTuple(type, createdObjectReferences);
+            }
+
+            Type[] genericArguments = type.GetGenericArguments();
+            if (genericArguments.Length == 1)
+            {
+                if (genericTypeDefinition == typeof(IList<>) ||
+                    genericTypeDefinition == typeof(IEnumerable<>) ||
+                    genericTypeDefinition == typeof(ICollection<>))
+                {
+                    Type collectionType = typeof(List<>).MakeGenericType(genericArguments);
+                    return GenerateCollection(collectionType, collectionSize, createdObjectReferences);
+                }
+
+                if (genericTypeDefinition == typeof(IQueryable<>))
+                {
+                    return GenerateQueryable(type, collectionSize, createdObjectReferences);
+                }
+
+                Type closedCollectionType = typeof(ICollection<>).MakeGenericType(genericArguments[0]);
+                if (closedCollectionType.IsAssignableFrom(type))
+                {
+                    return GenerateCollection(type, collectionSize, createdObjectReferences);
+                }
+            }
+
+            if (genericArguments.Length == 2)
+            {
+                if (genericTypeDefinition == typeof(IDictionary<,>))
+                {
+                    Type dictionaryType = typeof(Dictionary<,>).MakeGenericType(genericArguments);
+                    return GenerateDictionary(dictionaryType, collectionSize, createdObjectReferences);
+                }
+
+                Type closedDictionaryType = typeof(IDictionary<,>).MakeGenericType(genericArguments[0], genericArguments[1]);
+                if (closedDictionaryType.IsAssignableFrom(type))
+                {
+                    return GenerateDictionary(type, collectionSize, createdObjectReferences);
+                }
+            }
+
+            if (type.IsPublic || type.IsNestedPublic)
+            {
+                return GenerateComplexObject(type, createdObjectReferences);
+            }
+
+            return null;
+        }
+
+        private static object GenerateTuple(Type type, Dictionary<Type, object> createdObjectReferences)
+        {
+            Type[] genericArgs = type.GetGenericArguments();
+            object[] parameterValues = new object[genericArgs.Length];
+            bool failedToCreateTuple = true;
+            ObjectGenerator objectGenerator = new ObjectGenerator();
+            for (int i = 0; i < genericArgs.Length; i++)
+            {
+                parameterValues[i] = objectGenerator.GenerateObject(genericArgs[i], createdObjectReferences);
+                failedToCreateTuple &= parameterValues[i] == null;
+            }
+            if (failedToCreateTuple)
+            {
+                return null;
+            }
+            object result = Activator.CreateInstance(type, parameterValues);
+            return result;
+        }
+
+        private static bool IsTuple(Type genericTypeDefinition)
+        {
+            return genericTypeDefinition == typeof(Tuple<>) ||
+                genericTypeDefinition == typeof(Tuple<,>) ||
+                genericTypeDefinition == typeof(Tuple<,,>) ||
+                genericTypeDefinition == typeof(Tuple<,,,>) ||
+                genericTypeDefinition == typeof(Tuple<,,,,>) ||
+                genericTypeDefinition == typeof(Tuple<,,,,,>) ||
+                genericTypeDefinition == typeof(Tuple<,,,,,,>) ||
+                genericTypeDefinition == typeof(Tuple<,,,,,,,>);
+        }
+
+        private static object GenerateKeyValuePair(Type keyValuePairType, Dictionary<Type, object> createdObjectReferences)
+        {
+            Type[] genericArgs = keyValuePairType.GetGenericArguments();
+            Type typeK = genericArgs[0];
+            Type typeV = genericArgs[1];
+            ObjectGenerator objectGenerator = new ObjectGenerator();
+            object keyObject = objectGenerator.GenerateObject(typeK, createdObjectReferences);
+            object valueObject = objectGenerator.GenerateObject(typeV, createdObjectReferences);
+            if (keyObject == null && valueObject == null)
+            {
+                // Failed to create key and values
+                return null;
+            }
+            object result = Activator.CreateInstance(keyValuePairType, keyObject, valueObject);
+            return result;
+        }
+
+        private static object GenerateArray(Type arrayType, int size, Dictionary<Type, object> createdObjectReferences)
+        {
+            Type type = arrayType.GetElementType();
+            Array result = Array.CreateInstance(type, size);
+            bool areAllElementsNull = true;
+            ObjectGenerator objectGenerator = new ObjectGenerator();
+            for (int i = 0; i < size; i++)
+            {
+                object element = objectGenerator.GenerateObject(type, createdObjectReferences);
+                result.SetValue(element, i);
+                areAllElementsNull &= element == null;
+            }
+
+            if (areAllElementsNull)
+            {
+                return null;
+            }
+
+            return result;
+        }
+
+        private static object GenerateDictionary(Type dictionaryType, int size, Dictionary<Type, object> createdObjectReferences)
+        {
+            Type typeK = typeof(object);
+            Type typeV = typeof(object);
+            if (dictionaryType.IsGenericType)
+            {
+                Type[] genericArgs = dictionaryType.GetGenericArguments();
+                typeK = genericArgs[0];
+                typeV = genericArgs[1];
+            }
+
+            object result = Activator.CreateInstance(dictionaryType);
+            MethodInfo addMethod = dictionaryType.GetMethod("Add") ?? dictionaryType.GetMethod("TryAdd");
+            MethodInfo containsMethod = dictionaryType.GetMethod("Contains") ?? dictionaryType.GetMethod("ContainsKey");
+            ObjectGenerator objectGenerator = new ObjectGenerator();
+            for (int i = 0; i < size; i++)
+            {
+                object newKey = objectGenerator.GenerateObject(typeK, createdObjectReferences);
+                if (newKey == null)
+                {
+                    // Cannot generate a valid key
+                    return null;
+                }
+
+                bool containsKey = (bool)containsMethod.Invoke(result, new object[] { newKey });
+                if (!containsKey)
+                {
+                    object newValue = objectGenerator.GenerateObject(typeV, createdObjectReferences);
+                    addMethod.Invoke(result, new object[] { newKey, newValue });
+                }
+            }
+
+            return result;
+        }
+
+        private static object GenerateEnum(Type enumType)
+        {
+            Array possibleValues = Enum.GetValues(enumType);
+            if (possibleValues.Length > 0)
+            {
+                return possibleValues.GetValue(0);
+            }
+            return null;
+        }
+
+        private static object GenerateQueryable(Type queryableType, int size, Dictionary<Type, object> createdObjectReferences)
+        {
+            bool isGeneric = queryableType.IsGenericType;
+            object list;
+            if (isGeneric)
+            {
+                Type listType = typeof(List<>).MakeGenericType(queryableType.GetGenericArguments());
+                list = GenerateCollection(listType, size, createdObjectReferences);
+            }
+            else
+            {
+                list = GenerateArray(typeof(object[]), size, createdObjectReferences);
+            }
+            if (list == null)
+            {
+                return null;
+            }
+            if (isGeneric)
+            {
+                Type argumentType = typeof(IEnumerable<>).MakeGenericType(queryableType.GetGenericArguments());
+                MethodInfo asQueryableMethod = typeof(Queryable).GetMethod("AsQueryable", new[] { argumentType });
+                return asQueryableMethod.Invoke(null, new[] { list });
+            }
+
+            return Queryable.AsQueryable((IEnumerable)list);
+        }
+
+        private static object GenerateCollection(Type collectionType, int size, Dictionary<Type, object> createdObjectReferences)
+        {
+            Type type = collectionType.IsGenericType ?
+                collectionType.GetGenericArguments()[0] :
+                typeof(object);
+            object result = Activator.CreateInstance(collectionType);
+            MethodInfo addMethod = collectionType.GetMethod("Add");
+            bool areAllElementsNull = true;
+            ObjectGenerator objectGenerator = new ObjectGenerator();
+            for (int i = 0; i < size; i++)
+            {
+                object element = objectGenerator.GenerateObject(type, createdObjectReferences);
+                addMethod.Invoke(result, new object[] { element });
+                areAllElementsNull &= element == null;
+            }
+
+            if (areAllElementsNull)
+            {
+                return null;
+            }
+
+            return result;
+        }
+
+        private static object GenerateNullable(Type nullableType, Dictionary<Type, object> createdObjectReferences)
+        {
+            Type type = nullableType.GetGenericArguments()[0];
+            ObjectGenerator objectGenerator = new ObjectGenerator();
+            return objectGenerator.GenerateObject(type, createdObjectReferences);
+        }
+
+        private static object GenerateComplexObject(Type type, Dictionary<Type, object> createdObjectReferences)
+        {
+            object result = null;
+
+            if (createdObjectReferences.TryGetValue(type, out result))
+            {
+                // The object has been created already, just return it. This will handle the circular reference case.
+                return result;
+            }
+
+            if (type.IsValueType)
+            {
+                result = Activator.CreateInstance(type);
+            }
+            else
+            {
+                ConstructorInfo defaultCtor = type.GetConstructor(Type.EmptyTypes);
+                if (defaultCtor == null)
+                {
+                    // Cannot instantiate the type because it doesn't have a default constructor
+                    return null;
+                }
+
+                result = defaultCtor.Invoke(new object[0]);
+            }
+            createdObjectReferences.Add(type, result);
+            SetPublicProperties(type, result, createdObjectReferences);
+            SetPublicFields(type, result, createdObjectReferences);
+            return result;
+        }
+
+        private static void SetPublicProperties(Type type, object obj, Dictionary<Type, object> createdObjectReferences)
+        {
+            PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
+            ObjectGenerator objectGenerator = new ObjectGenerator();
+            foreach (PropertyInfo property in properties)
+            {
+                if (property.CanWrite)
+                {
+                    object propertyValue = objectGenerator.GenerateObject(property.PropertyType, createdObjectReferences);
+                    property.SetValue(obj, propertyValue, null);
+                }
+            }
+        }
+
+        private static void SetPublicFields(Type type, object obj, Dictionary<Type, object> createdObjectReferences)
+        {
+            FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
+            ObjectGenerator objectGenerator = new ObjectGenerator();
+            foreach (FieldInfo field in fields)
+            {
+                object fieldValue = objectGenerator.GenerateObject(field.FieldType, createdObjectReferences);
+                field.SetValue(obj, fieldValue);
+            }
+        }
+
+        private class SimpleTypeObjectGenerator
+        {
+            private long _index = 0;
+            private static readonly Dictionary<Type, Func<long, object>> DefaultGenerators = InitializeGenerators();
+
+            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "These are simple type factories and cannot be split up.")]
+            private static Dictionary<Type, Func<long, object>> InitializeGenerators()
+            {
+                return new Dictionary<Type, Func<long, object>>
+                {
+                    { typeof(Boolean), index => true },
+                    { typeof(Byte), index => (Byte)64 },
+                    { typeof(Char), index => (Char)65 },
+                    { typeof(DateTime), index => DateTime.Now },
+                    { typeof(DateTimeOffset), index => new DateTimeOffset(DateTime.Now) },
+                    { typeof(DBNull), index => DBNull.Value },
+                    { typeof(Decimal), index => (Decimal)index },
+                    { typeof(Double), index => (Double)(index + 0.1) },
+                    { typeof(Guid), index => Guid.NewGuid() },
+                    { typeof(Int16), index => (Int16)(index % Int16.MaxValue) },
+                    { typeof(Int32), index => (Int32)(index % Int32.MaxValue) },
+                    { typeof(Int64), index => (Int64)index },
+                    { typeof(Object), index => new object() },
+                    { typeof(SByte), index => (SByte)64 },
+                    { typeof(Single), index => (Single)(index + 0.1) },
+                    { 
+                        typeof(String), index =>
+                        {
+                            return String.Format(CultureInfo.CurrentCulture, "sample string {0}", index);
+                        }
+                    },
+                    { 
+                        typeof(TimeSpan), index =>
+                        {
+                            return TimeSpan.FromTicks(1234567);
+                        }
+                    },
+                    { typeof(UInt16), index => (UInt16)(index % UInt16.MaxValue) },
+                    { typeof(UInt32), index => (UInt32)(index % UInt32.MaxValue) },
+                    { typeof(UInt64), index => (UInt64)index },
+                    { 
+                        typeof(Uri), index =>
+                        {
+                            return new Uri(String.Format(CultureInfo.CurrentCulture, "http://webapihelppage{0}.com", index));
+                        }
+                    },
+                };
+            }
+
+            public static bool CanGenerateObject(Type type)
+            {
+                return DefaultGenerators.ContainsKey(type);
+            }
+
+            public object GenerateObject(Type type)
+            {
+                return DefaultGenerators[type](++_index);
+            }
+        }
+    }
+}

+ 11 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/SampleGeneration/SampleDirection.cs

@@ -0,0 +1,11 @@
+namespace VsdConverter.Areas.HelpPage
+{
+    /// <summary>
+    /// Indicates whether the sample is used for request or response
+    /// </summary>
+    public enum SampleDirection
+    {
+        Request = 0,
+        Response
+    }
+}

+ 37 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/SampleGeneration/TextSample.cs

@@ -0,0 +1,37 @@
+using System;
+
+namespace VsdConverter.Areas.HelpPage
+{
+    /// <summary>
+    /// This represents a preformatted text sample on the help page. There's a display template named TextSample associated with this class.
+    /// </summary>
+    public class TextSample
+    {
+        public TextSample(string text)
+        {
+            if (text == null)
+            {
+                throw new ArgumentNullException("text");
+            }
+            Text = text;
+        }
+
+        public string Text { get; private set; }
+
+        public override bool Equals(object obj)
+        {
+            TextSample other = obj as TextSample;
+            return other != null && Text == other.Text;
+        }
+
+        public override int GetHashCode()
+        {
+            return Text.GetHashCode();
+        }
+
+        public override string ToString()
+        {
+            return Text;
+        }
+    }
+}

+ 22 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/Api.cshtml

@@ -0,0 +1,22 @@
+@using System.Web.Http
+@using VsdConverter.Areas.HelpPage.Models
+@model HelpPageApiModel
+
+@{
+    var description = Model.ApiDescription;
+    ViewBag.Title = description.HttpMethod.Method + " " + description.RelativePath;
+}
+
+<link type="text/css" href="~/Areas/HelpPage/HelpPage.css" rel="stylesheet" />
+<div id="body" class="help-page">
+    <section class="featured">
+        <div class="content-wrapper">
+            <p>
+                @Html.ActionLink("Help Page Home", "Index")
+            </p>
+        </div>
+    </section>
+    <section class="content-wrapper main-content clear-fix">
+        @Html.DisplayForModel()
+    </section>
+</div>

+ 41 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/ApiGroup.cshtml

@@ -0,0 +1,41 @@
+@using System.Web.Http
+@using System.Web.Http.Controllers
+@using System.Web.Http.Description
+@using VsdConverter.Areas.HelpPage
+@using VsdConverter.Areas.HelpPage.Models
+@model IGrouping<HttpControllerDescriptor, ApiDescription>
+
+@{
+    var controllerDocumentation = ViewBag.DocumentationProvider != null ? 
+        ViewBag.DocumentationProvider.GetDocumentation(Model.Key) : 
+        null;
+}
+
+<h2 id="@Model.Key.ControllerName">@Model.Key.ControllerName</h2>
+@if (!String.IsNullOrEmpty(controllerDocumentation))
+{
+    <p>@controllerDocumentation</p>
+}
+<table class="help-page-table">
+    <thead>
+        <tr><th>API</th><th>Description</th></tr>
+    </thead>
+    <tbody>
+    @foreach (var api in Model)
+    {
+        <tr>
+            <td class="api-name"><a href="@Url.Action("Api", "Help", new { apiId = api.GetFriendlyId() })">@api.HttpMethod.Method @api.RelativePath</a></td>
+            <td class="api-documentation">
+            @if (api.Documentation != null)
+            {
+                <p>@api.Documentation</p>
+            }
+            else
+            {
+                <p>No documentation available.</p>
+            }
+            </td>
+        </tr>
+    }
+    </tbody>
+</table>

+ 6 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/CollectionModelDescription.cshtml

@@ -0,0 +1,6 @@
+@using VsdConverter.Areas.HelpPage.ModelDescriptions
+@model CollectionModelDescription
+@if (Model.ElementDescription is ComplexTypeModelDescription)
+{
+    @Html.DisplayFor(m => m.ElementDescription)
+}

+ 3 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/ComplexTypeModelDescription.cshtml

@@ -0,0 +1,3 @@
+@using VsdConverter.Areas.HelpPage.ModelDescriptions
+@model ComplexTypeModelDescription
+@Html.DisplayFor(m => m.Properties, "Parameters")

+ 4 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/DictionaryModelDescription.cshtml

@@ -0,0 +1,4 @@
+@using VsdConverter.Areas.HelpPage.ModelDescriptions
+@model DictionaryModelDescription
+Dictionary of @Html.DisplayFor(m => Model.KeyModelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.KeyModelDescription }) [key]
+and @Html.DisplayFor(m => Model.ValueModelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.ValueModelDescription }) [value]

+ 24 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/EnumTypeModelDescription.cshtml

@@ -0,0 +1,24 @@
+@using VsdConverter.Areas.HelpPage.ModelDescriptions
+@model EnumTypeModelDescription
+
+<p>Possible enumeration values:</p>
+
+<table class="help-page-table">
+    <thead>
+        <tr><th>Name</th><th>Value</th><th>Description</th></tr>
+    </thead>
+    <tbody>
+        @foreach (EnumValueDescription value in Model.Values)
+        {
+            <tr>
+                <td class="enum-name"><b>@value.Name</b></td>
+                <td class="enum-value">
+                    <p>@value.Value</p>
+                </td>
+                <td class="enum-description">
+                    <p>@value.Documentation</p>
+                </td>
+            </tr>
+        }
+    </tbody>
+</table>

+ 67 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/HelpPageApiModel.cshtml

@@ -0,0 +1,67 @@
+@using System.Web.Http
+@using System.Web.Http.Description
+@using VsdConverter.Areas.HelpPage.Models
+@using VsdConverter.Areas.HelpPage.ModelDescriptions
+@model HelpPageApiModel
+
+@{
+    ApiDescription description = Model.ApiDescription;
+}
+<h1>@description.HttpMethod.Method @description.RelativePath</h1>
+<div>
+    <p>@description.Documentation</p>
+
+    <h2>Request Information</h2>
+
+    <h3>URI Parameters</h3>
+    @Html.DisplayFor(m => m.UriParameters, "Parameters")
+
+    <h3>Body Parameters</h3>
+
+    <p>@Model.RequestDocumentation</p>
+
+    @if (Model.RequestModelDescription != null)
+    {
+        @Html.DisplayFor(m => m.RequestModelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.RequestModelDescription })
+        if (Model.RequestBodyParameters != null)
+        {
+            @Html.DisplayFor(m => m.RequestBodyParameters, "Parameters")
+        }
+    }
+    else
+    {
+        <p>None.</p>
+    }
+
+    @if (Model.SampleRequests.Count > 0)
+    {
+        <h3>Request Formats</h3>
+        @Html.DisplayFor(m => m.SampleRequests, "Samples")
+    }
+
+    <h2>Response Information</h2>
+
+    <h3>Resource Description</h3>
+
+    <p>@description.ResponseDescription.Documentation</p>
+
+    @if (Model.ResourceDescription != null)
+    {
+        @Html.DisplayFor(m => m.ResourceDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.ResourceDescription })
+        if (Model.ResourceProperties != null)
+        {
+            @Html.DisplayFor(m => m.ResourceProperties, "Parameters")
+        }
+    }
+    else
+    {
+        <p>None.</p>
+    }
+
+    @if (Model.SampleResponses.Count > 0)
+    {
+        <h3>Response Formats</h3>
+        @Html.DisplayFor(m => m.SampleResponses, "Samples")
+    }
+
+</div>

+ 4 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/ImageSample.cshtml

@@ -0,0 +1,4 @@
+@using VsdConverter.Areas.HelpPage
+@model ImageSample
+
+<img src="@Model.Src" />

+ 13 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/InvalidSample.cshtml

@@ -0,0 +1,13 @@
+@using VsdConverter.Areas.HelpPage
+@model InvalidSample
+
+@if (HttpContext.Current.IsDebuggingEnabled)
+{
+    <div class="warning-message-container">
+        <p>@Model.ErrorMessage</p>
+    </div>
+}
+else
+{
+    <p>Sample not available.</p>
+}

+ 4 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/KeyValuePairModelDescription.cshtml

@@ -0,0 +1,4 @@
+@using VsdConverter.Areas.HelpPage.ModelDescriptions
+@model KeyValuePairModelDescription
+Pair of @Html.DisplayFor(m => Model.KeyModelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.KeyModelDescription }) [key]
+and @Html.DisplayFor(m => Model.ValueModelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.ValueModelDescription }) [value]

+ 26 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/ModelDescriptionLink.cshtml

@@ -0,0 +1,26 @@
+@using VsdConverter.Areas.HelpPage.ModelDescriptions
+@model Type
+@{
+    ModelDescription modelDescription = ViewBag.modelDescription;
+    if (modelDescription is ComplexTypeModelDescription || modelDescription is EnumTypeModelDescription)
+    {
+        if (Model == typeof(Object))
+        {
+            @:Object
+        }
+        else
+        {
+            @Html.ActionLink(modelDescription.Name, "ResourceModel", "Help", new { modelName = modelDescription.Name }, null)
+        }
+    }
+    else if (modelDescription is CollectionModelDescription)
+    {
+        var collectionDescription = modelDescription as CollectionModelDescription;
+        var elementDescription = collectionDescription.ElementDescription;
+        @:Collection of @Html.DisplayFor(m => elementDescription.ModelType, "ModelDescriptionLink", new { modelDescription = elementDescription })
+    }
+    else
+    {
+        @Html.DisplayFor(m => modelDescription)
+    }
+}

+ 48 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/Parameters.cshtml

@@ -0,0 +1,48 @@
+@using System.Collections.Generic
+@using System.Collections.ObjectModel
+@using System.Web.Http.Description
+@using System.Threading
+@using VsdConverter.Areas.HelpPage.ModelDescriptions
+@model IList<ParameterDescription>
+
+@if (Model.Count > 0)
+{
+    <table class="help-page-table">
+        <thead>
+            <tr><th>Name</th><th>Description</th><th>Type</th><th>Additional information</th></tr>
+        </thead>
+        <tbody>
+            @foreach (ParameterDescription parameter in Model)
+            {
+                ModelDescription modelDescription = parameter.TypeDescription;
+                <tr>
+                    <td class="parameter-name">@parameter.Name</td>
+                    <td class="parameter-documentation">
+                        <p>@parameter.Documentation</p>
+                    </td>
+                    <td class="parameter-type">
+                        @Html.DisplayFor(m => modelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = modelDescription })
+                    </td>
+                    <td class="parameter-annotations">
+                        @if (parameter.Annotations.Count > 0)
+                        {
+                            foreach (var annotation in parameter.Annotations)
+                            {
+                                <p>@annotation.Documentation</p>
+                            }
+                        }
+                        else
+                        {
+                            <p>None.</p>
+                        }
+                    </td>
+                </tr>
+            }
+        </tbody>
+    </table>
+}
+else
+{
+    <p>None.</p>
+}
+

+ 30 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/Samples.cshtml

@@ -0,0 +1,30 @@
+@using System.Net.Http.Headers
+@model Dictionary<MediaTypeHeaderValue, object>
+
+@{
+    // Group the samples into a single tab if they are the same.
+    Dictionary<string, object> samples = Model.GroupBy(pair => pair.Value).ToDictionary(
+        pair => String.Join(", ", pair.Select(m => m.Key.ToString()).ToArray()), 
+        pair => pair.Key);
+    var mediaTypes = samples.Keys;
+}
+<div>
+    @foreach (var mediaType in mediaTypes)
+    {
+        <h4 class="sample-header">@mediaType</h4>
+        <div class="sample-content">
+            <span><b>Sample:</b></span>
+            @{
+                var sample = samples[mediaType];
+                if (sample == null)
+                {
+                    <p>Sample not available.</p>
+                }
+                else
+                {
+                    @Html.DisplayFor(s => sample);
+                }
+            }
+        </div>
+    }
+</div>

+ 3 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/SimpleTypeModelDescription.cshtml

@@ -0,0 +1,3 @@
+@using VsdConverter.Areas.HelpPage.ModelDescriptions
+@model SimpleTypeModelDescription
+@Model.Documentation

+ 6 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/DisplayTemplates/TextSample.cshtml

@@ -0,0 +1,6 @@
+@using VsdConverter.Areas.HelpPage
+@model TextSample
+
+<pre class="wrapped">
+@Model.Text
+</pre>

+ 38 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/Index.cshtml

@@ -0,0 +1,38 @@
+@using System.Web.Http
+@using System.Web.Http.Controllers
+@using System.Web.Http.Description
+@using System.Collections.ObjectModel
+@using VsdConverter.Areas.HelpPage.Models
+@model Collection<ApiDescription>
+
+@{
+    ViewBag.Title = "ASP.NET Web API Help Page";
+
+    // Group APIs by controller
+    ILookup<HttpControllerDescriptor, ApiDescription> apiGroups = Model.ToLookup(api => api.ActionDescriptor.ControllerDescriptor);
+}
+
+<link type="text/css" href="~/Areas/HelpPage/HelpPage.css" rel="stylesheet" />
+<header class="help-page">
+    <div class="content-wrapper">
+        <div class="float-left">
+            <h1>@ViewBag.Title</h1>
+        </div>
+    </div>
+</header>
+<div id="body" class="help-page">
+    <section class="featured">
+        <div class="content-wrapper">
+            <h2>Introduction</h2>
+            <p>
+                Provide a general description of your APIs here.
+            </p>
+        </div>
+    </section>
+    <section class="content-wrapper main-content clear-fix">
+        @foreach (var group in apiGroups)
+        {
+            @Html.DisplayFor(m => group, "ApiGroup")
+        }
+    </section>
+</div>

+ 19 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Help/ResourceModel.cshtml

@@ -0,0 +1,19 @@
+@using System.Web.Http
+@using VsdConverter.Areas.HelpPage.ModelDescriptions
+@model ModelDescription
+
+<link type="text/css" href="~/Areas/HelpPage/HelpPage.css" rel="stylesheet" />
+<div id="body" class="help-page">
+    <section class="featured">
+        <div class="content-wrapper">
+            <p>
+                @Html.ActionLink("Help Page Home", "Index")
+            </p>
+        </div>
+    </section>
+    <h1>@Model.Name</h1>
+    <p>@Model.Documentation</p>
+    <section class="content-wrapper main-content clear-fix">
+        @Html.DisplayFor(m => Model)
+    </section>
+</div>

+ 12 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Shared/_Layout.cshtml

@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8" />
+    <meta name="viewport" content="width=device-width" />
+    <title>@ViewBag.Title</title>
+    @RenderSection("scripts", required: false)
+</head>
+<body>
+    @RenderBody()
+</body>
+</html>

+ 41 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/Web.config

@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+
+<configuration>
+  <configSections>
+    <sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
+      <section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
+      <section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
+    </sectionGroup>
+  </configSections>
+
+  <system.web.webPages.razor>
+    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
+    <pages pageBaseType="System.Web.Mvc.WebViewPage">
+      <namespaces>
+        <add namespace="System.Web.Mvc" />
+        <add namespace="System.Web.Mvc.Ajax" />
+        <add namespace="System.Web.Mvc.Html" />
+        <add namespace="System.Web.Routing" />
+      </namespaces>
+    </pages>
+  </system.web.webPages.razor>
+
+  <appSettings>
+    <add key="webpages:Enabled" value="false" />
+  </appSettings>
+
+  <system.web>
+    <compilation debug="true">
+      <assemblies>
+        <add assembly="System.Net.Http, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
+      </assemblies>
+    </compilation>
+  </system.web>
+
+  <system.webServer>
+    <handlers>
+      <remove name="BlockViewHandler"/>
+      <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
+    </handlers>
+  </system.webServer>
+</configuration>

+ 4 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/Views/_ViewStart.cshtml

@@ -0,0 +1,4 @@
+@{
+    // Change the Layout path below to blend the look and feel of the help page with your existing web pages
+    Layout = "~/Views/Shared/_Layout.cshtml";
+}

+ 161 - 0
etc/vsd/VsdConverter/VsdConverter/Areas/HelpPage/XmlDocumentationProvider.cs

@@ -0,0 +1,161 @@
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using System.Web.Http.Controllers;
+using System.Web.Http.Description;
+using System.Xml.XPath;
+using VsdConverter.Areas.HelpPage.ModelDescriptions;
+
+namespace VsdConverter.Areas.HelpPage
+{
+    /// <summary>
+    /// A custom <see cref="IDocumentationProvider"/> that reads the API documentation from an XML documentation file.
+    /// </summary>
+    public class XmlDocumentationProvider : IDocumentationProvider, IModelDocumentationProvider
+    {
+        private XPathNavigator _documentNavigator;
+        private const string TypeExpression = "/doc/members/member[@name='T:{0}']";
+        private const string MethodExpression = "/doc/members/member[@name='M:{0}']";
+        private const string PropertyExpression = "/doc/members/member[@name='P:{0}']";
+        private const string FieldExpression = "/doc/members/member[@name='F:{0}']";
+        private const string ParameterExpression = "param[@name='{0}']";
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="XmlDocumentationProvider"/> class.
+        /// </summary>
+        /// <param name="documentPath">The physical path to XML document.</param>
+        public XmlDocumentationProvider(string documentPath)
+        {
+            if (documentPath == null)
+            {
+                throw new ArgumentNullException("documentPath");
+            }
+            XPathDocument xpath = new XPathDocument(documentPath);
+            _documentNavigator = xpath.CreateNavigator();
+        }
+
+        public string GetDocumentation(HttpControllerDescriptor controllerDescriptor)
+        {
+            XPathNavigator typeNode = GetTypeNode(controllerDescriptor.ControllerType);
+            return GetTagValue(typeNode, "summary");
+        }
+
+        public virtual string GetDocumentation(HttpActionDescriptor actionDescriptor)
+        {
+            XPathNavigator methodNode = GetMethodNode(actionDescriptor);
+            return GetTagValue(methodNode, "summary");
+        }
+
+        public virtual string GetDocumentation(HttpParameterDescriptor parameterDescriptor)
+        {
+            ReflectedHttpParameterDescriptor reflectedParameterDescriptor = parameterDescriptor as ReflectedHttpParameterDescriptor;
+            if (reflectedParameterDescriptor != null)
+            {
+                XPathNavigator methodNode = GetMethodNode(reflectedParameterDescriptor.ActionDescriptor);
+                if (methodNode != null)
+                {
+                    string parameterName = reflectedParameterDescriptor.ParameterInfo.Name;
+                    XPathNavigator parameterNode = methodNode.SelectSingleNode(String.Format(CultureInfo.InvariantCulture, ParameterExpression, parameterName));
+                    if (parameterNode != null)
+                    {
+                        return parameterNode.Value.Trim();
+                    }
+                }
+            }
+
+            return null;
+        }
+
+        public string GetResponseDocumentation(HttpActionDescriptor actionDescriptor)
+        {
+            XPathNavigator methodNode = GetMethodNode(actionDescriptor);
+            return GetTagValue(methodNode, "returns");
+        }
+
+        public string GetDocumentation(MemberInfo member)
+        {
+            string memberName = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", GetTypeName(member.DeclaringType), member.Name);
+            string expression = member.MemberType == MemberTypes.Field ? FieldExpression : PropertyExpression;
+            string selectExpression = String.Format(CultureInfo.InvariantCulture, expression, memberName);
+            XPathNavigator propertyNode = _documentNavigator.SelectSingleNode(selectExpression);
+            return GetTagValue(propertyNode, "summary");
+        }
+
+        public string GetDocumentation(Type type)
+        {
+            XPathNavigator typeNode = GetTypeNode(type);
+            return GetTagValue(typeNode, "summary");
+        }
+
+        private XPathNavigator GetMethodNode(HttpActionDescriptor actionDescriptor)
+        {
+            ReflectedHttpActionDescriptor reflectedActionDescriptor = actionDescriptor as ReflectedHttpActionDescriptor;
+            if (reflectedActionDescriptor != null)
+            {
+                string selectExpression = String.Format(CultureInfo.InvariantCulture, MethodExpression, GetMemberName(reflectedActionDescriptor.MethodInfo));
+                return _documentNavigator.SelectSingleNode(selectExpression);
+            }
+
+            return null;
+        }
+
+        private static string GetMemberName(MethodInfo method)
+        {
+            string name = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", GetTypeName(method.DeclaringType), method.Name);
+            ParameterInfo[] parameters = method.GetParameters();
+            if (parameters.Length != 0)
+            {
+                string[] parameterTypeNames = parameters.Select(param => GetTypeName(param.ParameterType)).ToArray();
+                name += String.Format(CultureInfo.InvariantCulture, "({0})", String.Join(",", parameterTypeNames));
+            }
+
+            return name;
+        }
+
+        private static string GetTagValue(XPathNavigator parentNode, string tagName)
+        {
+            if (parentNode != null)
+            {
+                XPathNavigator node = parentNode.SelectSingleNode(tagName);
+                if (node != null)
+                {
+                    return node.Value.Trim();
+                }
+            }
+
+            return null;
+        }
+
+        private XPathNavigator GetTypeNode(Type type)
+        {
+            string controllerTypeName = GetTypeName(type);
+            string selectExpression = String.Format(CultureInfo.InvariantCulture, TypeExpression, controllerTypeName);
+            return _documentNavigator.SelectSingleNode(selectExpression);
+        }
+
+        private static string GetTypeName(Type type)
+        {
+            string name = type.FullName;
+            if (type.IsGenericType)
+            {
+                // Format the generic type name to something like: Generic{System.Int32,System.String}
+                Type genericType = type.GetGenericTypeDefinition();
+                Type[] genericArguments = type.GetGenericArguments();
+                string genericTypeName = genericType.FullName;
+
+                // Trim the generic parameter counts from the name
+                genericTypeName = genericTypeName.Substring(0, genericTypeName.IndexOf('`'));
+                string[] argumentTypeNames = genericArguments.Select(t => GetTypeName(t)).ToArray();
+                name = String.Format(CultureInfo.InvariantCulture, "{0}{{{1}}}", genericTypeName, String.Join(",", argumentTypeNames));
+            }
+            if (type.IsNested)
+            {
+                // Changing the nested type name from OuterType+InnerType to OuterType.InnerType to match the XML documentation syntax.
+                name = name.Replace("+", ".");
+            }
+
+            return name;
+        }
+    }
+}

+ 17 - 0
etc/vsd/VsdConverter/VsdConverter/Content/Site.css

@@ -0,0 +1,17 @@
+body {
+    padding-top: 50px;
+    padding-bottom: 20px;
+}
+
+/* Set padding to keep content from hitting the edges */
+.body-content {
+    padding-left: 15px;
+    padding-right: 15px;
+}
+
+/* Set width on the form input elements since they're 100% wide by default */
+input,
+select,
+textarea {
+    max-width: 280px;
+}

File diff suppressed because it is too large
+ 6816 - 0
etc/vsd/VsdConverter/VsdConverter/Content/bootstrap.css


File diff suppressed because it is too large
+ 20 - 0
etc/vsd/VsdConverter/VsdConverter/Content/bootstrap.min.css


+ 192 - 0
etc/vsd/VsdConverter/VsdConverter/Controllers/ConverterController.cs

@@ -0,0 +1,192 @@
+using System;
+using System.Net;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+using System.Web;
+using System.Web.Http;
+using Ionic.Zip;
+using System.Collections.Generic;
+using System.IO;
+using System.Net.Sockets;
+using System.Net.Http.Headers;
+using System.Web.Http.Cors;
+
+namespace VsdConverter.Controllers
+{
+    [EnableCors(origins: "*", headers: "*", methods: "*")]
+    public class ConverterController : ApiController
+    {
+        static String Connect(String message)
+        {
+            try
+            {
+                Int32 port = 12355;
+                TcpClient client = new TcpClient("127.0.0.1", port);
+
+                // Translate the passed message into ASCII and store it as a Byte array.
+                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
+
+                NetworkStream stream = client.GetStream();
+
+                // Send the message to the connected TcpServer. 
+                stream.Write(data, 0, data.Length);
+
+                // Receive the TcpServer.response.
+
+                // Buffer to store the response bytes.
+                data = new Byte[256];
+
+                // String to store the response ASCII representation.
+                String responseData = String.Empty;
+
+                // Read the first batch of the TcpServer response bytes.
+                //This will block until the server finishes its work
+                Int32 bytes = stream.Read(data, 0, data.Length);
+                responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
+
+                // Close everything.
+                stream.Close();
+                client.Close();
+                return responseData;
+            }
+            catch (ArgumentNullException e)
+            {
+                Console.WriteLine("ArgumentNullException: {0}", e);
+            }
+            catch (SocketException e)
+            {
+                Console.WriteLine("SocketException: {0}", e);
+            }
+            return "Error";
+        }
+
+        public async Task<HttpResponseMessage> PostFile()
+        {
+            // Check if the request contains multipart/form-data.
+            if (!Request.Content.IsMimeMultipartContent())
+            {
+                throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
+            }
+
+            //TODO is this secure or it only returns the header?
+            String origin = Request.GetCorsRequestContext().Origin;
+
+            if (!origin.EndsWith("draw.io") && !origin.EndsWith("jgraph.com"))
+            {
+                throw new HttpResponseException(HttpStatusCode.Forbidden);
+            }
+
+            string root = HttpContext.Current.Server.MapPath("~/App_Data");
+            var provider = new MultipartFormDataStreamProvider(root);
+
+            List<string> files = new List<string>();
+            List<string> convertedFiles = new List<string>();
+            List<string> actualNames = new List<string>();
+
+            try
+            {
+                // Read the form data and return an async task.
+                await Request.Content.ReadAsMultipartAsync(provider);
+                
+                foreach (var file in provider.FileData)
+                {
+                    string actualFileName = file.Headers.ContentDisposition.FileName;
+                    if (actualFileName.EndsWith(".vsd\""))
+                    {
+                        convertedFiles.Add(file.LocalFileName);
+                        actualNames.Add(actualFileName);
+
+                        System.IO.File.Move(file.LocalFileName, file.LocalFileName + ".vsd");
+                    }
+                    else
+                    {
+                        files.Add(file.LocalFileName);
+                    }
+                }
+
+                StringBuilder allFiles = new StringBuilder();
+                String newLine = "";
+                for (int i = 0; i < convertedFiles.Count; i++)
+                {
+                    allFiles.Append(newLine);
+                    allFiles.Append(convertedFiles[i]);
+                    newLine = "\n";
+                }
+
+                //Ask the TCP Converter Server to do the job
+                //This will block until the server finishes the conversion
+                String resp = Connect(allFiles.ToString());
+
+                if ("Error".Equals(resp))
+                {
+                    throw new Exception("Coversion Failed");
+                }
+
+                if (convertedFiles.Count == 1)
+                {
+                    var pushStreamContent = new PushStreamContent((stream, content, context) =>
+                    {
+                        FileStream fs = new FileStream(convertedFiles[0] + ".vsdx", FileMode.Open);
+                        fs.CopyTo(stream);
+                        fs.Close();
+                        stream.Close(); // After save we close the stream to signal that we are done writing.
+
+                        System.IO.File.Delete(convertedFiles[0] + ".vsd");
+                        System.IO.File.Delete(convertedFiles[0] + ".vsdx");
+                    }, "application/x-visio");
+
+                    HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK) { Content = pushStreamContent };
+                    response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
+                    {
+                        FileName = Path.GetFileNameWithoutExtension(actualNames[0].Replace('"', ' ')) + ".vsdx"
+                    };
+                    response.Content.Headers.Add("Access-Control-Allow-Origin", "*");
+                    return response;
+                }
+                else
+                {
+                    using (var zipFile = new ZipFile())
+                    {
+                        for (int i = 0; i < convertedFiles.Count; i++)
+                        {
+                            var name = Path.GetFileNameWithoutExtension(actualNames[i].Replace('"', ' '));
+                            var file = convertedFiles[i];
+                            var e = zipFile.AddFile(file + ".vsdx");
+                            e.FileName = name + ".vsdx";
+                        }
+
+                        var pushStreamContent = new PushStreamContent((stream, content, context) =>
+                        {
+                            zipFile.Save(stream);
+                            stream.Close(); // After save we close the stream to signal that we are done writing.
+
+                            foreach (string file in convertedFiles)
+                            {
+                                System.IO.File.Delete(file + ".vsd");
+                                System.IO.File.Delete(file + ".vsdx");
+                            }
+                        }, "application/zip");
+
+                        HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK) { Content = pushStreamContent };
+                        response.Content.Headers.Add("Access-Control-Allow-Origin", "*");
+                        return response;
+                    }
+                }
+            }
+            catch (System.Exception e)
+            {
+                return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
+            }
+            finally
+            {
+                //clean all non-vsd files
+                foreach (string file in files)
+                {
+                    System.IO.File.Delete(file);
+                }
+            }
+        }
+
+    }
+}

+ 18 - 0
etc/vsd/VsdConverter/VsdConverter/Controllers/HomeController.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+using System.Web.Mvc;
+
+namespace VsdConverter.Controllers
+{
+    public class HomeController : Controller
+    {
+        public ActionResult Index()
+        {
+            ViewBag.Title = "Home Page";
+
+            return View();
+        }
+    }
+}

+ 1 - 0
etc/vsd/VsdConverter/VsdConverter/Global.asax

@@ -0,0 +1 @@
+<%@ Application Codebehind="Global.asax.cs" Inherits="VsdConverter.WebApiApplication" Language="C#" %>

+ 23 - 0
etc/vsd/VsdConverter/VsdConverter/Global.asax.cs

@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+using System.Web.Http;
+using System.Web.Mvc;
+using System.Web.Optimization;
+using System.Web.Routing;
+
+namespace VsdConverter
+{
+    public class WebApiApplication : System.Web.HttpApplication
+    {
+        protected void Application_Start()
+        {
+            AreaRegistration.RegisterAllAreas();
+            GlobalConfiguration.Configure(WebApiConfig.Register);
+            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
+            RouteConfig.RegisterRoutes(RouteTable.Routes);
+            BundleConfig.RegisterBundles(BundleTable.Bundles);
+        }
+    }
+}

+ 35 - 0
etc/vsd/VsdConverter/VsdConverter/Properties/AssemblyInfo.cs

@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("VsdConverter")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("VsdConverter")]
+[assembly: AssemblyCopyright("Copyright ©  2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("f2839167-3f8e-49f2-af45-ae1b6981aa14")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 21 - 0
etc/vsd/VsdConverter/VsdConverter/Properties/PublishProfiles/CustomProfile.pubxml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+This file is used by the publish/package process of your Web project. You can customize the behavior of this process
+by editing this MSBuild file. In order to learn more about this please visit https://go.microsoft.com/fwlink/?LinkID=208121. 
+-->
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <WebPublishMethod>Package</WebPublishMethod>
+    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
+    <LastUsedPlatform>Any CPU</LastUsedPlatform>
+    <SiteUrlToLaunchAfterPublish />
+    <LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
+    <ExcludeApp_Data>True</ExcludeApp_Data>
+    <DesktopBuildPackageLocation>C:\Users\ashra\source\VsdConverter.zip</DesktopBuildPackageLocation>
+    <PackageAsSingleFile>true</PackageAsSingleFile>
+    <DeployIisAppPath />
+    <PublishDatabaseSettings>
+      <Objects xmlns="" />
+    </PublishDatabaseSettings>
+  </PropertyGroup>
+</Project>

+ 10 - 0
etc/vsd/VsdConverter/VsdConverter/Properties/PublishProfiles/CustomProfile.pubxml.user

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+This file is used by the publish/package process of your Web project. You can customize the behavior of this process
+by editing this MSBuild file. In order to learn more about this please visit https://go.microsoft.com/fwlink/?LinkID=208121. 
+-->
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <TimeStampOfAssociatedLegacyPublishXmlFile />
+  </PropertyGroup>
+</Project>

+ 18 - 0
etc/vsd/VsdConverter/VsdConverter/Properties/PublishProfiles/FolderProfile.pubxml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+This file is used by the publish/package process of your Web project. You can customize the behavior of this process
+by editing this MSBuild file. In order to learn more about this please visit https://go.microsoft.com/fwlink/?LinkID=208121. 
+-->
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <WebPublishMethod>FileSystem</WebPublishMethod>
+    <PublishProvider>FileSystem</PublishProvider>
+    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
+    <LastUsedPlatform>Any CPU</LastUsedPlatform>
+    <SiteUrlToLaunchAfterPublish />
+    <LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
+    <ExcludeApp_Data>False</ExcludeApp_Data>
+    <publishUrl>bin\Release\PublishOutput</publishUrl>
+    <DeleteExistingFiles>False</DeleteExistingFiles>
+  </PropertyGroup>
+</Project>

+ 379 - 0
etc/vsd/VsdConverter/VsdConverter/Properties/PublishProfiles/FolderProfile.pubxml.user

@@ -0,0 +1,379 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+This file is used by the publish/package process of your Web project. You can customize the behavior of this process
+by editing this MSBuild file. In order to learn more about this please visit https://go.microsoft.com/fwlink/?LinkID=208121. 
+-->
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <TimeStampOfAssociatedLegacyPublishXmlFile />
+    <_PublishTargetUrl>C:\Users\ashra\source\repos\VsdConverter\VsdConverter\bin\Release\PublishOutput</_PublishTargetUrl>
+  </PropertyGroup>
+  <ItemGroup>
+    <File Include="ApplicationInsights.config">
+      <publishTime>12/28/2017 15:07:25</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/HelpPage.css">
+      <publishTime>12/28/2017 15:07:22</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/Api.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/ApiGroup.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/CollectionModelDescription.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/ComplexTypeModelDescription.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/DictionaryModelDescription.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/EnumTypeModelDescription.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/HelpPageApiModel.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/ImageSample.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/InvalidSample.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/KeyValuePairModelDescription.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/ModelDescriptionLink.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/Parameters.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/Samples.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/SimpleTypeModelDescription.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/TextSample.cshtml">
+      <publishTime>12/28/2017 15:07:19</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/Index.cshtml">
+      <publishTime>12/28/2017 15:07:19</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/ResourceModel.cshtml">
+      <publishTime>12/28/2017 15:07:19</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Shared/_Layout.cshtml">
+      <publishTime>12/28/2017 15:07:19</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Web.config">
+      <publishTime>12/28/2017 15:07:19</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/_ViewStart.cshtml">
+      <publishTime>12/28/2017 15:07:03</publishTime>
+    </File>
+    <File Include="bin/Antlr3.Runtime.dll">
+      <publishTime>02/22/2013 08:43:40</publishTime>
+    </File>
+    <File Include="bin/Antlr3.Runtime.pdb">
+      <publishTime>02/22/2013 08:43:40</publishTime>
+    </File>
+    <File Include="bin/ApplicationInsights.config">
+      <publishTime>12/28/2017 15:07:25</publishTime>
+    </File>
+    <File Include="bin/Ionic.Zip.dll">
+      <publishTime>11/22/2017 14:06:00</publishTime>
+    </File>
+    <File Include="bin/Microsoft.AI.Agent.Intercept.dll">
+      <publishTime>11/30/2016 16:07:42</publishTime>
+    </File>
+    <File Include="bin/Microsoft.AI.DependencyCollector.dll">
+      <publishTime>12/07/2016 11:45:42</publishTime>
+    </File>
+    <File Include="bin/Microsoft.AI.PerfCounterCollector.dll">
+      <publishTime>12/07/2016 11:50:34</publishTime>
+    </File>
+    <File Include="bin/Microsoft.AI.ServerTelemetryChannel.dll">
+      <publishTime>12/06/2016 15:15:48</publishTime>
+    </File>
+    <File Include="bin/Microsoft.AI.Web.dll">
+      <publishTime>12/07/2016 11:49:10</publishTime>
+    </File>
+    <File Include="bin/Microsoft.AI.WindowsServer.dll">
+      <publishTime>12/07/2016 11:50:34</publishTime>
+    </File>
+    <File Include="bin/Microsoft.ApplicationInsights.dll">
+      <publishTime>12/06/2016 15:09:52</publishTime>
+    </File>
+    <File Include="bin/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll">
+      <publishTime>08/15/2017 13:12:32</publishTime>
+    </File>
+    <File Include="bin/Microsoft.Management.Infrastructure.dll">
+      <publishTime>07/17/2017 14:46:10</publishTime>
+    </File>
+    <File Include="bin/Microsoft.Web.Infrastructure.dll">
+      <publishTime>01/05/2012 11:08:46</publishTime>
+    </File>
+    <File Include="bin/Newtonsoft.Json.dll">
+      <publishTime>08/03/2014 20:33:56</publishTime>
+    </File>
+    <File Include="bin/roslyn/csc.exe">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/csc.exe.config">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/csc.rsp">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/csi.exe">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/csi.exe.config">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/csi.rsp">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.Build.Tasks.CodeAnalysis.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.CodeAnalysis.CSharp.dll">
+      <publishTime>04/13/2017 15:47:46</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.CodeAnalysis.CSharp.Scripting.dll">
+      <publishTime>04/13/2017 15:47:46</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.CodeAnalysis.dll">
+      <publishTime>04/13/2017 15:47:46</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.CodeAnalysis.Scripting.dll">
+      <publishTime>04/13/2017 15:47:46</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.CodeAnalysis.VisualBasic.dll">
+      <publishTime>04/13/2017 15:47:46</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.CSharp.Core.targets">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.DiaSymReader.Native.amd64.dll">
+      <publishTime>04/13/2017 15:47:46</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.DiaSymReader.Native.x86.dll">
+      <publishTime>04/13/2017 15:47:46</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.VisualBasic.Core.targets">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.Win32.Primitives.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.AppContext.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Collections.Immutable.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Console.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Diagnostics.FileVersionInfo.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Diagnostics.Process.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Diagnostics.StackTrace.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.IO.Compression.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.IO.FileSystem.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.IO.FileSystem.DriveInfo.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.IO.FileSystem.Primitives.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.IO.Pipes.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Reflection.Metadata.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Security.AccessControl.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Security.Claims.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Security.Cryptography.Algorithms.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Security.Cryptography.Encoding.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Security.Cryptography.Primitives.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Security.Cryptography.X509Certificates.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Security.Principal.Windows.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Text.Encoding.CodePages.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Threading.Thread.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.ValueTuple.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Xml.ReaderWriter.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Xml.XmlDocument.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Xml.XPath.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Xml.XPath.XDocument.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/vbc.exe">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/vbc.exe.config">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/vbc.rsp">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/VBCSCompiler.exe">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/VBCSCompiler.exe.config">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/System.Management.Automation.dll">
+      <publishTime>07/17/2017 14:46:10</publishTime>
+    </File>
+    <File Include="bin/System.Net.Http.Formatting.dll">
+      <publishTime>01/28/2015 04:02:42</publishTime>
+    </File>
+    <File Include="bin/System.Web.Helpers.dll">
+      <publishTime>01/28/2015 04:04:30</publishTime>
+    </File>
+    <File Include="bin/System.Web.Http.dll">
+      <publishTime>01/28/2015 04:02:54</publishTime>
+    </File>
+    <File Include="bin/System.Web.Http.WebHost.dll">
+      <publishTime>01/28/2015 04:03:46</publishTime>
+    </File>
+    <File Include="bin/System.Web.Mvc.dll">
+      <publishTime>01/28/2015 04:02:18</publishTime>
+    </File>
+    <File Include="bin/System.Web.Optimization.dll">
+      <publishTime>02/11/2014 15:26:04</publishTime>
+    </File>
+    <File Include="bin/System.Web.Razor.dll">
+      <publishTime>01/28/2015 04:02:32</publishTime>
+    </File>
+    <File Include="bin/System.Web.WebPages.Deployment.dll">
+      <publishTime>01/28/2015 04:04:30</publishTime>
+    </File>
+    <File Include="bin/System.Web.WebPages.dll">
+      <publishTime>01/28/2015 04:04:30</publishTime>
+    </File>
+    <File Include="bin/System.Web.WebPages.Razor.dll">
+      <publishTime>01/28/2015 04:04:30</publishTime>
+    </File>
+    <File Include="bin/VsdConverter.dll">
+      <publishTime>12/29/2017 16:37:55</publishTime>
+    </File>
+    <File Include="bin/VsdConverter.pdb">
+      <publishTime>12/29/2017 16:37:55</publishTime>
+    </File>
+    <File Include="bin/WebGrease.dll">
+      <publishTime>09/10/2013 17:28:38</publishTime>
+    </File>
+    <File Include="Content/bootstrap.css">
+      <publishTime>12/28/2017 15:07:10</publishTime>
+    </File>
+    <File Include="Content/bootstrap.min.css">
+      <publishTime>12/28/2017 15:07:10</publishTime>
+    </File>
+    <File Include="Content/Site.css">
+      <publishTime>12/28/2017 15:07:03</publishTime>
+    </File>
+    <File Include="favicon.ico">
+      <publishTime>12/28/2017 15:07:03</publishTime>
+    </File>
+    <File Include="fonts/glyphicons-halflings-regular.eot">
+      <publishTime>12/28/2017 15:07:10</publishTime>
+    </File>
+    <File Include="fonts/glyphicons-halflings-regular.svg">
+      <publishTime>12/28/2017 15:07:10</publishTime>
+    </File>
+    <File Include="fonts/glyphicons-halflings-regular.ttf">
+      <publishTime>12/28/2017 15:07:10</publishTime>
+    </File>
+    <File Include="fonts/glyphicons-halflings-regular.woff">
+      <publishTime>12/28/2017 15:07:10</publishTime>
+    </File>
+    <File Include="Global.asax">
+      <publishTime>12/28/2017 15:07:03</publishTime>
+    </File>
+    <File Include="Scripts/bootstrap.js">
+      <publishTime>12/28/2017 15:07:10</publishTime>
+    </File>
+    <File Include="Scripts/bootstrap.min.js">
+      <publishTime>12/28/2017 15:07:10</publishTime>
+    </File>
+    <File Include="Scripts/jquery-1.10.2.js">
+      <publishTime>12/28/2017 15:07:14</publishTime>
+    </File>
+    <File Include="Scripts/jquery-1.10.2.min.js">
+      <publishTime>12/28/2017 15:07:14</publishTime>
+    </File>
+    <File Include="Scripts/jquery-1.10.2.min.map">
+      <publishTime>12/28/2017 15:07:14</publishTime>
+    </File>
+    <File Include="Scripts/modernizr-2.6.2.js">
+      <publishTime>12/28/2017 15:07:22</publishTime>
+    </File>
+    <File Include="Scripts/respond.js">
+      <publishTime>12/28/2017 15:07:24</publishTime>
+    </File>
+    <File Include="Scripts/respond.min.js">
+      <publishTime>12/28/2017 15:07:24</publishTime>
+    </File>
+    <File Include="Views/Home/Index.cshtml">
+      <publishTime>12/29/2017 16:08:55</publishTime>
+    </File>
+    <File Include="Views/Shared/Error.cshtml">
+      <publishTime>12/28/2017 15:07:03</publishTime>
+    </File>
+    <File Include="Views/Shared/_Layout.cshtml">
+      <publishTime>12/28/2017 15:07:03</publishTime>
+    </File>
+    <File Include="Views/Web.config">
+      <publishTime>12/28/2017 15:07:03</publishTime>
+    </File>
+    <File Include="Views/_ViewStart.cshtml">
+      <publishTime>12/28/2017 15:07:03</publishTime>
+    </File>
+    <File Include="Web.config">
+      <publishTime>12/29/2017 16:37:56</publishTime>
+    </File>
+  </ItemGroup>
+</Project>

+ 17 - 0
etc/vsd/VsdConverter/VsdConverter/Properties/PublishProfiles/FolderProfile1.pubxml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+This file is used by the publish/package process of your Web project. You can customize the behavior of this process
+by editing this MSBuild file. In order to learn more about this please visit https://go.microsoft.com/fwlink/?LinkID=208121. 
+-->
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <WebPublishMethod>FileSystem</WebPublishMethod>
+    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
+    <LastUsedPlatform>x64</LastUsedPlatform>
+    <SiteUrlToLaunchAfterPublish />
+    <LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
+    <ExcludeApp_Data>False</ExcludeApp_Data>
+    <publishUrl>C:\newApp\AppPkg</publishUrl>
+    <DeleteExistingFiles>False</DeleteExistingFiles>
+  </PropertyGroup>
+</Project>

+ 385 - 0
etc/vsd/VsdConverter/VsdConverter/Properties/PublishProfiles/FolderProfile1.pubxml.user

@@ -0,0 +1,385 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+This file is used by the publish/package process of your Web project. You can customize the behavior of this process
+by editing this MSBuild file. In order to learn more about this please visit https://go.microsoft.com/fwlink/?LinkID=208121. 
+-->
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <TimeStampOfAssociatedLegacyPublishXmlFile />
+    <_PublishTargetUrl>C:\newApp\AppPkg</_PublishTargetUrl>
+  </PropertyGroup>
+  <ItemGroup>
+    <File Include="ApplicationInsights.config">
+      <publishTime>12/28/2017 15:07:25</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/HelpPage.css">
+      <publishTime>12/28/2017 15:07:22</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/Api.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/ApiGroup.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/CollectionModelDescription.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/ComplexTypeModelDescription.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/DictionaryModelDescription.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/EnumTypeModelDescription.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/HelpPageApiModel.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/ImageSample.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/InvalidSample.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/KeyValuePairModelDescription.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/ModelDescriptionLink.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/Parameters.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/Samples.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/SimpleTypeModelDescription.cshtml">
+      <publishTime>12/28/2017 15:07:20</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/DisplayTemplates/TextSample.cshtml">
+      <publishTime>12/28/2017 15:07:19</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/Index.cshtml">
+      <publishTime>12/28/2017 15:07:19</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Help/ResourceModel.cshtml">
+      <publishTime>12/28/2017 15:07:19</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Shared/_Layout.cshtml">
+      <publishTime>12/28/2017 15:07:19</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/Web.config">
+      <publishTime>03/30/2018 14:53:40</publishTime>
+    </File>
+    <File Include="Areas/HelpPage/Views/_ViewStart.cshtml">
+      <publishTime>12/28/2017 15:07:03</publishTime>
+    </File>
+    <File Include="bin/Antlr3.Runtime.dll">
+      <publishTime>02/22/2013 08:43:40</publishTime>
+    </File>
+    <File Include="bin/Antlr3.Runtime.pdb">
+      <publishTime>02/22/2013 08:43:40</publishTime>
+    </File>
+    <File Include="bin/ApplicationInsights.config">
+      <publishTime>12/28/2017 15:07:25</publishTime>
+    </File>
+    <File Include="bin/Ionic.Zip.dll">
+      <publishTime>11/22/2017 14:06:00</publishTime>
+    </File>
+    <File Include="bin/Microsoft.AI.Agent.Intercept.dll">
+      <publishTime>11/30/2016 16:07:42</publishTime>
+    </File>
+    <File Include="bin/Microsoft.AI.DependencyCollector.dll">
+      <publishTime>12/07/2016 11:45:42</publishTime>
+    </File>
+    <File Include="bin/Microsoft.AI.PerfCounterCollector.dll">
+      <publishTime>12/07/2016 11:50:34</publishTime>
+    </File>
+    <File Include="bin/Microsoft.AI.ServerTelemetryChannel.dll">
+      <publishTime>12/06/2016 15:15:48</publishTime>
+    </File>
+    <File Include="bin/Microsoft.AI.Web.dll">
+      <publishTime>12/07/2016 11:49:10</publishTime>
+    </File>
+    <File Include="bin/Microsoft.AI.WindowsServer.dll">
+      <publishTime>12/07/2016 11:50:34</publishTime>
+    </File>
+    <File Include="bin/Microsoft.ApplicationInsights.dll">
+      <publishTime>12/06/2016 15:09:52</publishTime>
+    </File>
+    <File Include="bin/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll">
+      <publishTime>08/15/2017 13:12:32</publishTime>
+    </File>
+    <File Include="bin/Microsoft.Management.Infrastructure.dll">
+      <publishTime>07/17/2017 14:46:10</publishTime>
+    </File>
+    <File Include="bin/Microsoft.Web.Infrastructure.dll">
+      <publishTime>01/05/2012 11:08:46</publishTime>
+    </File>
+    <File Include="bin/Newtonsoft.Json.dll">
+      <publishTime>08/03/2014 20:33:56</publishTime>
+    </File>
+    <File Include="bin/roslyn/csc.exe">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/csc.exe.config">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/csc.rsp">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/csi.exe">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/csi.exe.config">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/csi.rsp">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.Build.Tasks.CodeAnalysis.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.CodeAnalysis.CSharp.dll">
+      <publishTime>04/13/2017 15:47:46</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.CodeAnalysis.CSharp.Scripting.dll">
+      <publishTime>04/13/2017 15:47:46</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.CodeAnalysis.dll">
+      <publishTime>04/13/2017 15:47:46</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.CodeAnalysis.Scripting.dll">
+      <publishTime>04/13/2017 15:47:46</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.CodeAnalysis.VisualBasic.dll">
+      <publishTime>04/13/2017 15:47:46</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.CSharp.Core.targets">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.DiaSymReader.Native.amd64.dll">
+      <publishTime>04/13/2017 15:47:46</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.DiaSymReader.Native.x86.dll">
+      <publishTime>04/13/2017 15:47:46</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.VisualBasic.Core.targets">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/Microsoft.Win32.Primitives.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.AppContext.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Collections.Immutable.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Console.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Diagnostics.FileVersionInfo.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Diagnostics.Process.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Diagnostics.StackTrace.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.IO.Compression.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.IO.FileSystem.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.IO.FileSystem.DriveInfo.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.IO.FileSystem.Primitives.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.IO.Pipes.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Reflection.Metadata.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Security.AccessControl.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Security.Claims.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Security.Cryptography.Algorithms.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Security.Cryptography.Encoding.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Security.Cryptography.Primitives.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Security.Cryptography.X509Certificates.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Security.Principal.Windows.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Text.Encoding.CodePages.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Threading.Thread.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.ValueTuple.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Xml.ReaderWriter.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Xml.XmlDocument.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Xml.XPath.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/System.Xml.XPath.XDocument.dll">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/vbc.exe">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/vbc.exe.config">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/vbc.rsp">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/VBCSCompiler.exe">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/roslyn/VBCSCompiler.exe.config">
+      <publishTime>04/13/2017 15:47:48</publishTime>
+    </File>
+    <File Include="bin/System.Management.Automation.dll">
+      <publishTime>07/17/2017 14:46:10</publishTime>
+    </File>
+    <File Include="bin/System.Net.Http.Formatting.dll">
+      <publishTime>02/01/2018 12:17:18</publishTime>
+    </File>
+    <File Include="bin/System.Web.Cors.dll">
+      <publishTime>02/01/2018 12:15:30</publishTime>
+    </File>
+    <File Include="bin/System.Web.Helpers.dll">
+      <publishTime>01/28/2015 04:04:30</publishTime>
+    </File>
+    <File Include="bin/System.Web.Http.Cors.dll">
+      <publishTime>02/01/2018 12:18:02</publishTime>
+    </File>
+    <File Include="bin/System.Web.Http.dll">
+      <publishTime>02/01/2018 12:17:40</publishTime>
+    </File>
+    <File Include="bin/System.Web.Http.WebHost.dll">
+      <publishTime>01/28/2015 04:03:46</publishTime>
+    </File>
+    <File Include="bin/System.Web.Mvc.dll">
+      <publishTime>01/28/2015 04:02:18</publishTime>
+    </File>
+    <File Include="bin/System.Web.Optimization.dll">
+      <publishTime>02/11/2014 15:26:04</publishTime>
+    </File>
+    <File Include="bin/System.Web.Razor.dll">
+      <publishTime>01/28/2015 04:02:32</publishTime>
+    </File>
+    <File Include="bin/System.Web.WebPages.Deployment.dll">
+      <publishTime>01/28/2015 04:04:30</publishTime>
+    </File>
+    <File Include="bin/System.Web.WebPages.dll">
+      <publishTime>01/28/2015 04:04:30</publishTime>
+    </File>
+    <File Include="bin/System.Web.WebPages.Razor.dll">
+      <publishTime>01/28/2015 04:04:30</publishTime>
+    </File>
+    <File Include="bin/VsdConverter.dll">
+      <publishTime>03/31/2018 17:49:17</publishTime>
+    </File>
+    <File Include="bin/VsdConverter.pdb">
+      <publishTime>03/31/2018 17:49:17</publishTime>
+    </File>
+    <File Include="bin/WebGrease.dll">
+      <publishTime>09/10/2013 17:28:38</publishTime>
+    </File>
+    <File Include="Content/bootstrap.css">
+      <publishTime>12/28/2017 15:07:10</publishTime>
+    </File>
+    <File Include="Content/bootstrap.min.css">
+      <publishTime>12/28/2017 15:07:10</publishTime>
+    </File>
+    <File Include="Content/Site.css">
+      <publishTime>12/28/2017 15:07:03</publishTime>
+    </File>
+    <File Include="favicon.ico">
+      <publishTime>12/28/2017 15:07:03</publishTime>
+    </File>
+    <File Include="fonts/glyphicons-halflings-regular.eot">
+      <publishTime>12/28/2017 15:07:10</publishTime>
+    </File>
+    <File Include="fonts/glyphicons-halflings-regular.svg">
+      <publishTime>12/28/2017 15:07:10</publishTime>
+    </File>
+    <File Include="fonts/glyphicons-halflings-regular.ttf">
+      <publishTime>12/28/2017 15:07:10</publishTime>
+    </File>
+    <File Include="fonts/glyphicons-halflings-regular.woff">
+      <publishTime>12/28/2017 15:07:10</publishTime>
+    </File>
+    <File Include="Global.asax">
+      <publishTime>12/28/2017 15:07:03</publishTime>
+    </File>
+    <File Include="Scripts/bootstrap.js">
+      <publishTime>12/28/2017 15:07:10</publishTime>
+    </File>
+    <File Include="Scripts/bootstrap.min.js">
+      <publishTime>12/28/2017 15:07:10</publishTime>
+    </File>
+    <File Include="Scripts/jquery-1.10.2.js">
+      <publishTime>12/28/2017 15:07:14</publishTime>
+    </File>
+    <File Include="Scripts/jquery-1.10.2.min.js">
+      <publishTime>12/28/2017 15:07:14</publishTime>
+    </File>
+    <File Include="Scripts/jquery-1.10.2.min.map">
+      <publishTime>12/28/2017 15:07:14</publishTime>
+    </File>
+    <File Include="Scripts/modernizr-2.6.2.js">
+      <publishTime>12/28/2017 15:07:22</publishTime>
+    </File>
+    <File Include="Scripts/respond.js">
+      <publishTime>12/28/2017 15:07:24</publishTime>
+    </File>
+    <File Include="Scripts/respond.min.js">
+      <publishTime>12/28/2017 15:07:24</publishTime>
+    </File>
+    <File Include="Views/Home/Index.cshtml">
+      <publishTime>03/30/2018 15:59:48</publishTime>
+    </File>
+    <File Include="Views/Shared/Error.cshtml">
+      <publishTime>12/28/2017 15:07:03</publishTime>
+    </File>
+    <File Include="Views/Shared/_Layout.cshtml">
+      <publishTime>12/28/2017 15:07:03</publishTime>
+    </File>
+    <File Include="Views/Web.config">
+      <publishTime>03/30/2018 14:53:40</publishTime>
+    </File>
+    <File Include="Views/_ViewStart.cshtml">
+      <publishTime>12/28/2017 15:07:03</publishTime>
+    </File>
+    <File Include="Web.config">
+      <publishTime>03/31/2018 17:49:18</publishTime>
+    </File>
+  </ItemGroup>
+</Project>

File diff suppressed because it is too large
+ 2014 - 0
etc/vsd/VsdConverter/VsdConverter/Scripts/bootstrap.js


File diff suppressed because it is too large
+ 21 - 0
etc/vsd/VsdConverter/VsdConverter/Scripts/bootstrap.min.js


File diff suppressed because it is too large
+ 2671 - 0
etc/vsd/VsdConverter/VsdConverter/Scripts/jquery-1.10.2.intellisense.js


File diff suppressed because it is too large
+ 9803 - 0
etc/vsd/VsdConverter/VsdConverter/Scripts/jquery-1.10.2.js


File diff suppressed because it is too large
+ 23 - 0
etc/vsd/VsdConverter/VsdConverter/Scripts/jquery-1.10.2.min.js


File diff suppressed because it is too large
+ 1 - 0
etc/vsd/VsdConverter/VsdConverter/Scripts/jquery-1.10.2.min.map


File diff suppressed because it is too large
+ 1416 - 0
etc/vsd/VsdConverter/VsdConverter/Scripts/modernizr-2.6.2.js


+ 340 - 0
etc/vsd/VsdConverter/VsdConverter/Scripts/respond.js

@@ -0,0 +1,340 @@
+/* NUGET: BEGIN LICENSE TEXT
+ *
+ * Microsoft grants you the right to use these script files for the sole
+ * purpose of either: (i) interacting through your browser with the Microsoft
+ * website or online service, subject to the applicable licensing or use
+ * terms; or (ii) using the files as included with a Microsoft product subject
+ * to that product's license terms. Microsoft reserves all other rights to the
+ * files not expressly granted by Microsoft, whether by implication, estoppel
+ * or otherwise. Insofar as a script file is dual licensed under GPL,
+ * Microsoft neither took the code under GPL nor distributes it thereunder but
+ * under the terms set out in this paragraph. All notices and licenses
+ * below are for informational purposes only.
+ *
+ * NUGET: END LICENSE TEXT */
+/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
+/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
+window.matchMedia = window.matchMedia || (function(doc, undefined){
+  
+  var bool,
+      docElem  = doc.documentElement,
+      refNode  = docElem.firstElementChild || docElem.firstChild,
+      // fakeBody required for <FF4 when executed in <head>
+      fakeBody = doc.createElement('body'),
+      div      = doc.createElement('div');
+  
+  div.id = 'mq-test-1';
+  div.style.cssText = "position:absolute;top:-100em";
+  fakeBody.style.background = "none";
+  fakeBody.appendChild(div);
+  
+  return function(q){
+    
+    div.innerHTML = '&shy;<style media="'+q+'"> #mq-test-1 { width: 42px; }</style>';
+    
+    docElem.insertBefore(fakeBody, refNode);
+    bool = div.offsetWidth == 42;  
+    docElem.removeChild(fakeBody);
+    
+    return { matches: bool, media: q };
+  };
+  
+})(document);
+
+
+
+
+/*! Respond.js v1.2.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs  */
+(function( win ){
+	//exposed namespace
+	win.respond		= {};
+	
+	//define update even in native-mq-supporting browsers, to avoid errors
+	respond.update	= function(){};
+	
+	//expose media query support flag for external use
+	respond.mediaQueriesSupported	= win.matchMedia && win.matchMedia( "only all" ).matches;
+	
+	//if media queries are supported, exit here
+	if( respond.mediaQueriesSupported ){ return; }
+	
+	//define vars
+	var doc 			= win.document,
+		docElem 		= doc.documentElement,
+		mediastyles		= [],
+		rules			= [],
+		appendedEls 	= [],
+		parsedSheets 	= {},
+		resizeThrottle	= 30,
+		head 			= doc.getElementsByTagName( "head" )[0] || docElem,
+		base			= doc.getElementsByTagName( "base" )[0],
+		links			= head.getElementsByTagName( "link" ),
+		requestQueue	= [],
+		
+		//loop stylesheets, send text content to translate
+		ripCSS			= function(){
+			var sheets 	= links,
+				sl 		= sheets.length,
+				i		= 0,
+				//vars for loop:
+				sheet, href, media, isCSS;
+
+			for( ; i < sl; i++ ){
+				sheet	= sheets[ i ],
+				href	= sheet.href,
+				media	= sheet.media,
+				isCSS	= sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
+
+				//only links plz and prevent re-parsing
+				if( !!href && isCSS && !parsedSheets[ href ] ){
+					// selectivizr exposes css through the rawCssText expando
+					if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
+						translate( sheet.styleSheet.rawCssText, href, media );
+						parsedSheets[ href ] = true;
+					} else {
+						if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base)
+							|| href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){
+							requestQueue.push( {
+								href: href,
+								media: media
+							} );
+						}
+					}
+				}
+			}
+			makeRequests();
+		},
+		
+		//recurse through request queue, get css text
+		makeRequests	= function(){
+			if( requestQueue.length ){
+				var thisRequest = requestQueue.shift();
+				
+				ajax( thisRequest.href, function( styles ){
+					translate( styles, thisRequest.href, thisRequest.media );
+					parsedSheets[ thisRequest.href ] = true;
+					makeRequests();
+				} );
+			}
+		},
+		
+		//find media blocks in css text, convert to style blocks
+		translate			= function( styles, href, media ){
+			var qs			= styles.match(  /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi ),
+				ql			= qs && qs.length || 0,
+				//try to get CSS path
+				href		= href.substring( 0, href.lastIndexOf( "/" )),
+				repUrls		= function( css ){
+					return css.replace( /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g, "$1" + href + "$2$3" );
+				},
+				useMedia	= !ql && media,
+				//vars used in loop
+				i			= 0,
+				j, fullq, thisq, eachq, eql;
+
+			//if path exists, tack on trailing slash
+			if( href.length ){ href += "/"; }	
+				
+			//if no internal queries exist, but media attr does, use that	
+			//note: this currently lacks support for situations where a media attr is specified on a link AND
+				//its associated stylesheet has internal CSS media queries.
+				//In those cases, the media attribute will currently be ignored.
+			if( useMedia ){
+				ql = 1;
+			}
+			
+
+			for( ; i < ql; i++ ){
+				j	= 0;
+				
+				//media attr
+				if( useMedia ){
+					fullq = media;
+					rules.push( repUrls( styles ) );
+				}
+				//parse for styles
+				else{
+					fullq	= qs[ i ].match( /@media *([^\{]+)\{([\S\s]+?)$/ ) && RegExp.$1;
+					rules.push( RegExp.$2 && repUrls( RegExp.$2 ) );
+				}
+				
+				eachq	= fullq.split( "," );
+				eql		= eachq.length;
+					
+				for( ; j < eql; j++ ){
+					thisq	= eachq[ j ];
+					mediastyles.push( { 
+						media	: thisq.split( "(" )[ 0 ].match( /(only\s+)?([a-zA-Z]+)\s?/ ) && RegExp.$2 || "all",
+						rules	: rules.length - 1,
+						hasquery: thisq.indexOf("(") > -1,
+						minw	: thisq.match( /\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ), 
+						maxw	: thisq.match( /\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" )
+					} );
+				}	
+			}
+
+			applyMedia();
+		},
+        	
+		lastCall,
+		
+		resizeDefer,
+		
+		// returns the value of 1em in pixels
+		getEmValue		= function() {
+			var ret,
+				div = doc.createElement('div'),
+				body = doc.body,
+				fakeUsed = false;
+									
+			div.style.cssText = "position:absolute;font-size:1em;width:1em";
+					
+			if( !body ){
+				body = fakeUsed = doc.createElement( "body" );
+				body.style.background = "none";
+			}
+					
+			body.appendChild( div );
+								
+			docElem.insertBefore( body, docElem.firstChild );
+								
+			ret = div.offsetWidth;
+								
+			if( fakeUsed ){
+				docElem.removeChild( body );
+			}
+			else {
+				body.removeChild( div );
+			}
+			
+			//also update eminpx before returning
+			ret = eminpx = parseFloat(ret);
+								
+			return ret;
+		},
+		
+		//cached container for 1em value, populated the first time it's needed 
+		eminpx,
+		
+		//enable/disable styles
+		applyMedia			= function( fromResize ){
+			var name		= "clientWidth",
+				docElemProp	= docElem[ name ],
+				currWidth 	= doc.compatMode === "CSS1Compat" && docElemProp || doc.body[ name ] || docElemProp,
+				styleBlocks	= {},
+				lastLink	= links[ links.length-1 ],
+				now 		= (new Date()).getTime();
+
+			//throttle resize calls	
+			if( fromResize && lastCall && now - lastCall < resizeThrottle ){
+				clearTimeout( resizeDefer );
+				resizeDefer = setTimeout( applyMedia, resizeThrottle );
+				return;
+			}
+			else {
+				lastCall	= now;
+			}
+										
+			for( var i in mediastyles ){
+				var thisstyle = mediastyles[ i ],
+					min = thisstyle.minw,
+					max = thisstyle.maxw,
+					minnull = min === null,
+					maxnull = max === null,
+					em = "em";
+				
+				if( !!min ){
+					min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
+				}
+				if( !!max ){
+					max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
+				}
+				
+				// if there's no media query at all (the () part), or min or max is not null, and if either is present, they're true
+				if( !thisstyle.hasquery || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max ) ){
+						if( !styleBlocks[ thisstyle.media ] ){
+							styleBlocks[ thisstyle.media ] = [];
+						}
+						styleBlocks[ thisstyle.media ].push( rules[ thisstyle.rules ] );
+				}
+			}
+			
+			//remove any existing respond style element(s)
+			for( var i in appendedEls ){
+				if( appendedEls[ i ] && appendedEls[ i ].parentNode === head ){
+					head.removeChild( appendedEls[ i ] );
+				}
+			}
+			
+			//inject active styles, grouped by media type
+			for( var i in styleBlocks ){
+				var ss		= doc.createElement( "style" ),
+					css		= styleBlocks[ i ].join( "\n" );
+				
+				ss.type = "text/css";	
+				ss.media	= i;
+				
+				//originally, ss was appended to a documentFragment and sheets were appended in bulk.
+				//this caused crashes in IE in a number of circumstances, such as when the HTML element had a bg image set, so appending beforehand seems best. Thanks to @dvelyk for the initial research on this one!
+				head.insertBefore( ss, lastLink.nextSibling );
+				
+				if ( ss.styleSheet ){ 
+		        	ss.styleSheet.cssText = css;
+		        } 
+		        else {
+					ss.appendChild( doc.createTextNode( css ) );
+		        }
+		        
+				//push to appendedEls to track for later removal
+				appendedEls.push( ss );
+			}
+		},
+		//tweaked Ajax functions from Quirksmode
+		ajax = function( url, callback ) {
+			var req = xmlHttp();
+			if (!req){
+				return;
+			}	
+			req.open( "GET", url, true );
+			req.onreadystatechange = function () {
+				if ( req.readyState != 4 || req.status != 200 && req.status != 304 ){
+					return;
+				}
+				callback( req.responseText );
+			}
+			if ( req.readyState == 4 ){
+				return;
+			}
+			req.send( null );
+		},
+		//define ajax obj 
+		xmlHttp = (function() {
+			var xmlhttpmethod = false;	
+			try {
+				xmlhttpmethod = new XMLHttpRequest();
+			}
+			catch( e ){
+				xmlhttpmethod = new ActiveXObject( "Microsoft.XMLHTTP" );
+			}
+			return function(){
+				return xmlhttpmethod;
+			};
+		})();
+	
+	//translate CSS
+	ripCSS();
+	
+	//expose update for re-running respond later on
+	respond.update = ripCSS;
+	
+	//adjust on resize
+	function callMedia(){
+		applyMedia( true );
+	}
+	if( win.addEventListener ){
+		win.addEventListener( "resize", callMedia, false );
+	}
+	else if( win.attachEvent ){
+		win.attachEvent( "onresize", callMedia );
+	}
+})(this);

File diff suppressed because it is too large
+ 20 - 0
etc/vsd/VsdConverter/VsdConverter/Scripts/respond.min.js


+ 30 - 0
etc/vsd/VsdConverter/VsdConverter/Views/Home/Index.cshtml

@@ -0,0 +1,30 @@
+<div id="body">
+	<section class="main-content clear-fix">
+
+		<form name="form1" method="post" enctype="multipart/form-data" action="api/converter">
+            <fieldset>
+                <legend>*.vsd Files</legend>
+                <div>
+                    <label for="file1">File 1</label>
+                    <input name="file1" type="file" />
+                </div>
+                <div>
+                    <label for="file2">File 2</label>
+                    <input name="file2" type="file" />
+                </div>
+                <div>
+                    <label for="file3">File 3</label>
+                    <input name="file3" type="file" />
+                </div>
+                <div>
+                    <label for="file4">File 4</label>
+                    <input name="file4" type="file" />
+                </div>
+                <div>
+                    <input type="submit" value="Submit" />
+                </div>
+            </fieldset>
+		</form>
+
+	</section>
+</div>

+ 13 - 0
etc/vsd/VsdConverter/VsdConverter/Views/Shared/Error.cshtml

@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta name="viewport" content="width=device-width" />
+    <title>Error</title>
+</head>
+<body>
+    <hgroup>
+        <h1>Error.</h1>
+        <h2>An error occurred while processing your request.</h2>
+    </hgroup>
+</body>
+</html>

+ 41 - 0
etc/vsd/VsdConverter/VsdConverter/Views/Shared/_Layout.cshtml

@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8" />
+    <meta name="viewport" content="width=device-width" />
+    <title>@ViewBag.Title</title>
+    @Styles.Render("~/Content/css")
+    @Scripts.Render("~/bundles/modernizr")
+</head>
+<body>
+    <div class="navbar navbar-inverse navbar-fixed-top">
+        <div class="container">
+            <div class="navbar-header">
+                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
+                    <span class="icon-bar"></span>
+                    <span class="icon-bar"></span>
+                    <span class="icon-bar"></span>
+                </button>
+                @Html.ActionLink("Application name", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
+            </div>
+            <div class="navbar-collapse collapse">
+                <ul class="nav navbar-nav">
+                    <li>@Html.ActionLink("Home", "Index", "Home", new { area = "" }, null)</li>
+                    <li>@Html.ActionLink("API", "Index", "Help", new { area = "" }, null)</li>
+                </ul>
+            </div>
+        </div>
+    </div>
+    <div class="container body-content">
+        @RenderBody()
+        <hr />
+        <footer>
+            <p>&copy; @DateTime.Now.Year - My ASP.NET Application</p>
+        </footer>
+    </div>
+
+    @Scripts.Render("~/bundles/jquery")
+    @Scripts.Render("~/bundles/bootstrap")
+    @RenderSection("scripts", required: false)
+</body>
+</html>

+ 43 - 0
etc/vsd/VsdConverter/VsdConverter/Views/Web.config

@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+
+<configuration>
+  <configSections>
+    <sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
+      <section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
+      <section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
+    </sectionGroup>
+  </configSections>
+
+  <system.web.webPages.razor>
+    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
+    <pages pageBaseType="System.Web.Mvc.WebViewPage">
+      <namespaces>
+        <add namespace="System.Web.Mvc" />
+        <add namespace="System.Web.Mvc.Ajax" />
+        <add namespace="System.Web.Mvc.Html" />
+        <add namespace="System.Web.Optimization"/>
+        <add namespace="System.Web.Routing" />
+        <add namespace="VsdConverter" />
+      </namespaces>
+    </pages>
+  </system.web.webPages.razor>
+
+  <appSettings>
+    <add key="webpages:Enabled" value="false" />
+  </appSettings>
+
+  <system.webServer>
+    <handlers>
+      <remove name="BlockViewHandler"/>
+      <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
+    </handlers>
+  </system.webServer>
+
+  <system.web>
+    <compilation>
+      <assemblies>
+        <add assembly="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
+      </assemblies>
+    </compilation>
+  </system.web>
+</configuration>

+ 3 - 0
etc/vsd/VsdConverter/VsdConverter/Views/_ViewStart.cshtml

@@ -0,0 +1,3 @@
+@{
+    Layout = "~/Views/Shared/_Layout.cshtml";
+}

+ 344 - 0
etc/vsd/VsdConverter/VsdConverter/VsdConverter.csproj

@@ -0,0 +1,344 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.7\build\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props" Condition="Exists('..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.7\build\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')" />
+  <Import Project="..\packages\Microsoft.Net.Compilers.2.1.0\build\Microsoft.Net.Compilers.props" Condition="Exists('..\packages\Microsoft.Net.Compilers.2.1.0\build\Microsoft.Net.Compilers.props')" />
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>
+    </ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{61D7B18D-2DBB-411F-8854-7EAB3C226C37}</ProjectGuid>
+    <ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>VsdConverter</RootNamespace>
+    <AssemblyName>VsdConverter</AssemblyName>
+    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+    <MvcBuildViews>false</MvcBuildViews>
+    <UseIISExpress>true</UseIISExpress>
+    <Use64BitIISExpress />
+    <IISExpressSSLPort />
+    <IISExpressAnonymousAuthentication />
+    <IISExpressWindowsAuthentication />
+    <IISExpressUseClassicPipelineMode />
+    <UseGlobalApplicationHostFile />
+    <NuGetPackageImportStamp>
+    </NuGetPackageImportStamp>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Ionic.Zip, Version=1.9.1.8, Culture=neutral, PublicKeyToken=edbe51ad942a3f5c, processorArchitecture=MSIL">
+      <HintPath>..\packages\Ionic.Zip.1.9.1.8\lib\Ionic.Zip.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.7\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.PowerShell.5.ReferenceAssemblies.1.1.0\lib\net4\System.Management.Automation.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System.Net.Http.Formatting, Version=5.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.AspNet.WebApi.Client.5.2.4\lib\net45\System.Net.Http.Formatting.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.Cors, Version=5.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.AspNet.Cors.5.2.4\lib\net45\System.Web.Cors.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.Entity" />
+    <Reference Include="System.Web.ApplicationServices" />
+    <Reference Include="System.ComponentModel.DataAnnotations" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="System.Web.Http, Version=5.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.AspNet.WebApi.Core.5.2.4\lib\net45\System.Web.Http.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.Http.Cors, Version=5.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.AspNet.WebApi.Cors.5.2.4\lib\net45\System.Web.Http.Cors.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Web" />
+    <Reference Include="System.Web.Abstractions" />
+    <Reference Include="System.Web.Routing" />
+    <Reference Include="System.Xml" />
+    <Reference Include="System.Configuration" />
+    <Reference Include="System.Runtime.Serialization" />
+    <Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json">
+      <HintPath>..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Net.Http">
+    </Reference>
+    <Reference Include="System.Net.Http.WebRequest">
+    </Reference>
+    <Reference Include="System.Web.Helpers, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.Http.WebHost, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.Optimization">
+      <HintPath>..\packages\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.WebPages.Deployment, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll</HintPath>
+    </Reference>
+    <Reference Include="WebGrease">
+      <Private>True</Private>
+      <HintPath>..\packages\WebGrease.1.5.2\lib\WebGrease.dll</HintPath>
+    </Reference>
+    <Reference Include="Antlr3.Runtime">
+      <Private>True</Private>
+      <HintPath>..\packages\Antlr.3.4.1.9004\lib\Antlr3.Runtime.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Reference Include="Microsoft.ApplicationInsights">
+      <HintPath>..\packages\Microsoft.ApplicationInsights.2.2.0\lib\net45\Microsoft.ApplicationInsights.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.AI.Agent.Intercept">
+      <HintPath>..\packages\Microsoft.ApplicationInsights.Agent.Intercept.2.0.6\lib\net45\Microsoft.AI.Agent.Intercept.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.AI.DependencyCollector">
+      <HintPath>..\packages\Microsoft.ApplicationInsights.DependencyCollector.2.2.0\lib\net45\Microsoft.AI.DependencyCollector.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.AI.PerfCounterCollector">
+      <HintPath>..\packages\Microsoft.ApplicationInsights.PerfCounterCollector.2.2.0\lib\net45\Microsoft.AI.PerfCounterCollector.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.AI.ServerTelemetryChannel">
+      <HintPath>..\packages\Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.2.2.0\lib\net45\Microsoft.AI.ServerTelemetryChannel.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.AI.WindowsServer">
+      <HintPath>..\packages\Microsoft.ApplicationInsights.WindowsServer.2.2.0\lib\net45\Microsoft.AI.WindowsServer.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.AI.Web">
+      <HintPath>..\packages\Microsoft.ApplicationInsights.Web.2.2.0\lib\net45\Microsoft.AI.Web.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="App_Start\BundleConfig.cs" />
+    <Compile Include="App_Start\FilterConfig.cs" />
+    <Compile Include="App_Start\RouteConfig.cs" />
+    <Compile Include="App_Start\WebApiConfig.cs" />
+    <Compile Include="Areas\HelpPage\ApiDescriptionExtensions.cs" />
+    <Compile Include="Areas\HelpPage\App_Start\HelpPageConfig.cs" />
+    <Compile Include="Areas\HelpPage\Controllers\HelpController.cs" />
+    <Compile Include="Areas\HelpPage\HelpPageAreaRegistration.cs" />
+    <Compile Include="Areas\HelpPage\HelpPageConfigurationExtensions.cs" />
+    <Compile Include="Areas\HelpPage\ModelDescriptions\CollectionModelDescription.cs" />
+    <Compile Include="Areas\HelpPage\ModelDescriptions\ComplexTypeModelDescription.cs" />
+    <Compile Include="Areas\HelpPage\ModelDescriptions\DictionaryModelDescription.cs" />
+    <Compile Include="Areas\HelpPage\ModelDescriptions\EnumTypeModelDescription.cs" />
+    <Compile Include="Areas\HelpPage\ModelDescriptions\EnumValueDescription.cs" />
+    <Compile Include="Areas\HelpPage\ModelDescriptions\IModelDocumentationProvider.cs" />
+    <Compile Include="Areas\HelpPage\ModelDescriptions\KeyValuePairModelDescription.cs" />
+    <Compile Include="Areas\HelpPage\ModelDescriptions\ModelDescription.cs" />
+    <Compile Include="Areas\HelpPage\ModelDescriptions\ModelDescriptionGenerator.cs" />
+    <Compile Include="Areas\HelpPage\ModelDescriptions\ModelNameAttribute.cs" />
+    <Compile Include="Areas\HelpPage\ModelDescriptions\ModelNameHelper.cs" />
+    <Compile Include="Areas\HelpPage\ModelDescriptions\ParameterAnnotation.cs" />
+    <Compile Include="Areas\HelpPage\ModelDescriptions\ParameterDescription.cs" />
+    <Compile Include="Areas\HelpPage\ModelDescriptions\SimpleTypeModelDescription.cs" />
+    <Compile Include="Areas\HelpPage\Models\HelpPageApiModel.cs" />
+    <Compile Include="Areas\HelpPage\SampleGeneration\HelpPageSampleGenerator.cs" />
+    <Compile Include="Areas\HelpPage\SampleGeneration\HelpPageSampleKey.cs" />
+    <Compile Include="Areas\HelpPage\SampleGeneration\ImageSample.cs" />
+    <Compile Include="Areas\HelpPage\SampleGeneration\InvalidSample.cs" />
+    <Compile Include="Areas\HelpPage\SampleGeneration\ObjectGenerator.cs" />
+    <Compile Include="Areas\HelpPage\SampleGeneration\SampleDirection.cs" />
+    <Compile Include="Areas\HelpPage\SampleGeneration\TextSample.cs" />
+    <Compile Include="Areas\HelpPage\XmlDocumentationProvider.cs" />
+    <Compile Include="Controllers\ConverterController.cs" />
+    <Compile Include="Controllers\HomeController.cs" />
+    <Compile Include="Global.asax.cs">
+      <DependentUpon>Global.asax</DependentUpon>
+    </Compile>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="Areas\HelpPage\HelpPage.css" />
+    <Content Include="Content\bootstrap.css" />
+    <Content Include="Content\bootstrap.min.css" />
+    <Content Include="favicon.ico" />
+    <Content Include="fonts\glyphicons-halflings-regular.svg" />
+    <Content Include="Global.asax" />
+    <Content Include="Scripts\bootstrap.js" />
+    <Content Include="Scripts\bootstrap.min.js" />
+    <Content Include="Areas\HelpPage\Views\Web.config" />
+    <Content Include="Areas\HelpPage\Views\Shared\_Layout.cshtml" />
+    <Content Include="Areas\HelpPage\Views\Help\ResourceModel.cshtml" />
+    <Content Include="Areas\HelpPage\Views\Help\Index.cshtml" />
+    <Content Include="Areas\HelpPage\Views\Help\DisplayTemplates\TextSample.cshtml" />
+    <Content Include="Areas\HelpPage\Views\Help\DisplayTemplates\SimpleTypeModelDescription.cshtml" />
+    <Content Include="Areas\HelpPage\Views\Help\DisplayTemplates\Samples.cshtml" />
+    <Content Include="Areas\HelpPage\Views\Help\DisplayTemplates\Parameters.cshtml" />
+    <Content Include="Areas\HelpPage\Views\Help\DisplayTemplates\ModelDescriptionLink.cshtml" />
+    <Content Include="Areas\HelpPage\Views\Help\DisplayTemplates\KeyValuePairModelDescription.cshtml" />
+    <Content Include="Areas\HelpPage\Views\Help\DisplayTemplates\InvalidSample.cshtml" />
+    <Content Include="Areas\HelpPage\Views\Help\DisplayTemplates\ImageSample.cshtml" />
+    <Content Include="Areas\HelpPage\Views\Help\DisplayTemplates\HelpPageApiModel.cshtml" />
+    <Content Include="Areas\HelpPage\Views\Help\DisplayTemplates\EnumTypeModelDescription.cshtml" />
+    <Content Include="Areas\HelpPage\Views\Help\DisplayTemplates\DictionaryModelDescription.cshtml" />
+    <Content Include="Areas\HelpPage\Views\Help\DisplayTemplates\ComplexTypeModelDescription.cshtml" />
+    <Content Include="Areas\HelpPage\Views\Help\DisplayTemplates\CollectionModelDescription.cshtml" />
+    <Content Include="Areas\HelpPage\Views\Help\DisplayTemplates\ApiGroup.cshtml" />
+    <Content Include="Areas\HelpPage\Views\Help\Api.cshtml" />
+    <Content Include="ApplicationInsights.config">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <None Include="Properties\PublishProfiles\CustomProfile.pubxml" />
+    <None Include="Properties\PublishProfiles\FolderProfile.pubxml" />
+    <None Include="Properties\PublishProfiles\FolderProfile1.pubxml" />
+    <None Include="Scripts\jquery-1.10.2.intellisense.js" />
+    <Content Include="Scripts\jquery-1.10.2.js" />
+    <Content Include="Scripts\jquery-1.10.2.min.js" />
+    <Content Include="Scripts\modernizr-2.6.2.js" />
+    <Content Include="Scripts\respond.js" />
+    <Content Include="Scripts\respond.min.js" />
+    <Content Include="Web.config" />
+    <Content Include="Web.Debug.config">
+      <DependentUpon>Web.config</DependentUpon>
+    </Content>
+    <Content Include="Web.Release.config">
+      <DependentUpon>Web.config</DependentUpon>
+    </Content>
+    <Content Include="Areas\HelpPage\Views\_ViewStart.cshtml" />
+    <Content Include="Content\Site.css" />
+    <Content Include="Views\Web.config" />
+    <Content Include="Views\_ViewStart.cshtml" />
+    <Content Include="Views\Home\Index.cshtml" />
+    <Content Include="Views\Shared\Error.cshtml" />
+    <Content Include="Views\Shared\_Layout.cshtml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="App_Code\" />
+    <Folder Include="App_Data\" />
+    <Folder Include="Models\" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="fonts\glyphicons-halflings-regular.woff" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="fonts\glyphicons-halflings-regular.ttf" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="fonts\glyphicons-halflings-regular.eot" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+    <Content Include="Scripts\jquery-1.10.2.min.map" />
+  </ItemGroup>
+  <ItemGroup>
+    <COMReference Include="stdole">
+      <Guid>{00020430-0000-0000-C000-000000000046}</Guid>
+      <VersionMajor>2</VersionMajor>
+      <VersionMinor>0</VersionMinor>
+      <Lcid>0</Lcid>
+      <WrapperTool>primary</WrapperTool>
+      <Isolated>False</Isolated>
+      <EmbedInteropTypes>True</EmbedInteropTypes>
+    </COMReference>
+  </ItemGroup>
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
+  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
+  <Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
+    <AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
+  </Target>
+  <ProjectExtensions>
+    <VisualStudio>
+      <FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
+        <WebProjectProperties>
+          <UseIIS>True</UseIIS>
+          <AutoAssignPort>True</AutoAssignPort>
+          <DevelopmentServerPort>59769</DevelopmentServerPort>
+          <DevelopmentServerVPath>/</DevelopmentServerVPath>
+          <IISUrl>http://localhost:59769/</IISUrl>
+          <NTLMAuthentication>False</NTLMAuthentication>
+          <UseCustomServer>False</UseCustomServer>
+          <CustomServerUrl>
+          </CustomServerUrl>
+          <SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
+        </WebProjectProperties>
+      </FlavorProperties>
+    </VisualStudio>
+  </ProjectExtensions>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('..\packages\Microsoft.Net.Compilers.2.1.0\build\Microsoft.Net.Compilers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Net.Compilers.2.1.0\build\Microsoft.Net.Compilers.props'))" />
+    <Error Condition="!Exists('..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.7\build\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.7\build\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props'))" />
+  </Target>
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target> -->
+</Project>

+ 46 - 0
etc/vsd/VsdConverter/VsdConverter/VsdConverter.csproj.user

@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <UseIISExpress>true</UseIISExpress>
+    <Use64BitIISExpress />
+    <IISExpressSSLPort />
+    <IISExpressAnonymousAuthentication />
+    <IISExpressWindowsAuthentication />
+    <IISExpressUseClassicPipelineMode />
+    <UseGlobalApplicationHostFile />
+    <Controller_SelectedScaffolderID>ApiControllerEmptyScaffolder</Controller_SelectedScaffolderID>
+    <Controller_SelectedScaffolderCategoryPath>root/Controller</Controller_SelectedScaffolderCategoryPath>
+    <WebStackScaffolding_ControllerDialogWidth>600</WebStackScaffolding_ControllerDialogWidth>
+    <WebStackScaffolding_IsLayoutPageSelected>True</WebStackScaffolding_IsLayoutPageSelected>
+    <WebStackScaffolding_IsPartialViewSelected>False</WebStackScaffolding_IsPartialViewSelected>
+    <WebStackScaffolding_IsReferencingScriptLibrariesSelected>True</WebStackScaffolding_IsReferencingScriptLibrariesSelected>
+    <WebStackScaffolding_LayoutPageFile />
+    <WebStackScaffolding_IsAsyncSelected>False</WebStackScaffolding_IsAsyncSelected>
+    <NameOfLastUsedPublishProfile>FolderProfile1</NameOfLastUsedPublishProfile>
+  </PropertyGroup>
+  <ProjectExtensions>
+    <VisualStudio>
+      <FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
+        <WebProjectProperties>
+          <StartPageUrl>
+          </StartPageUrl>
+          <StartAction>CurrentPage</StartAction>
+          <AspNetDebugging>True</AspNetDebugging>
+          <SilverlightDebugging>False</SilverlightDebugging>
+          <NativeDebugging>False</NativeDebugging>
+          <SQLDebugging>False</SQLDebugging>
+          <ExternalProgram>
+          </ExternalProgram>
+          <StartExternalURL>
+          </StartExternalURL>
+          <StartCmdLineArguments>
+          </StartCmdLineArguments>
+          <StartWorkingDirectory>
+          </StartWorkingDirectory>
+          <EnableENC>True</EnableENC>
+          <AlwaysStartWebServerOnDebug>True</AlwaysStartWebServerOnDebug>
+        </WebProjectProperties>
+      </FlavorProperties>
+    </VisualStudio>
+  </ProjectExtensions>
+</Project>

+ 30 - 0
etc/vsd/VsdConverter/VsdConverter/Web.Debug.config

@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+
+<!-- For more information on using Web.config transformation visit https://go.microsoft.com/fwlink/?LinkId=301874 -->
+
+<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
+  <!--
+    In the example below, the "SetAttributes" transform will change the value of
+    "connectionString" to use "ReleaseSQLServer" only when the "Match" locator
+    finds an attribute "name" that has a value of "MyDB".
+
+    <connectionStrings>
+      <add name="MyDB"
+        connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
+        xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
+    </connectionStrings>
+  -->
+  <system.web>
+    <!--
+      In the example below, the "Replace" transform will replace the entire
+      <customErrors> section of your Web.config file.
+      Note that because there is only one customErrors section under the
+      <system.web> node, there is no need to use the "xdt:Locator" attribute.
+
+      <customErrors defaultRedirect="GenericError.htm"
+        mode="RemoteOnly" xdt:Transform="Replace">
+        <error statusCode="500" redirect="InternalError.htm"/>
+      </customErrors>
+    -->
+  </system.web>
+</configuration>

+ 31 - 0
etc/vsd/VsdConverter/VsdConverter/Web.Release.config

@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+
+<!-- For more information on using Web.config transformation visit https://go.microsoft.com/fwlink/?LinkId=301874 -->
+
+<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
+  <!--
+    In the example below, the "SetAttributes" transform will change the value of
+    "connectionString" to use "ReleaseSQLServer" only when the "Match" locator
+    finds an attribute "name" that has a value of "MyDB".
+
+    <connectionStrings>
+      <add name="MyDB"
+        connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
+        xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
+    </connectionStrings>
+  -->
+  <system.web>
+    <compilation xdt:Transform="RemoveAttributes(debug)" />
+    <!--
+      In the example below, the "Replace" transform will replace the entire
+      <customErrors> section of your Web.config file.
+      Note that because there is only one customErrors section under the
+      <system.web> node, there is no need to use the "xdt:Locator" attribute.
+
+      <customErrors defaultRedirect="GenericError.htm"
+        mode="RemoteOnly" xdt:Transform="Replace">
+        <error statusCode="500" redirect="InternalError.htm"/>
+      </customErrors>
+    -->
+  </system.web>
+</configuration>

+ 75 - 0
etc/vsd/VsdConverter/VsdConverter/Web.config

@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  For more information on how to configure your ASP.NET application, please visit
+  https://go.microsoft.com/fwlink/?LinkId=301879
+  -->
+<configuration>
+  <appSettings>
+    <add key="webpages:Version" value="3.0.0.0" />
+    <add key="webpages:Enabled" value="false" />
+    <add key="ClientValidationEnabled" value="true" />
+    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
+  </appSettings>
+  <system.web>
+    <compilation debug="true" targetFramework="4.6.1" />
+    <httpRuntime targetFramework="4.6.1" />
+    <httpModules>
+      <add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" />
+    </httpModules>
+  </system.web>
+  <system.webServer>
+    
+    <validation validateIntegratedModeConfiguration="false" />
+    <modules>
+      <remove name="ApplicationInsightsWebTracking" />
+      <add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" preCondition="managedHandler" />
+    </modules>
+  <handlers>
+      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
+      <remove name="OPTIONSVerbHandler" />
+      <remove name="TRACEVerbHandler" />
+      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+    </handlers></system.webServer>
+  <runtime>
+    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+      <dependentAssembly>
+        <assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed" />
+        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-5.2.4.0" newVersion="5.2.4.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-5.2.4.0" newVersion="5.2.4.0" />
+      </dependentAssembly>
+    </assemblyBinding>
+  </runtime>
+  <system.codedom>
+    <compilers>
+      <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:1659;1699;1701" />
+      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+" />
+    </compilers>
+  </system.codedom>
+</configuration>

BIN
etc/vsd/VsdConverter/VsdConverter/favicon.ico


BIN
etc/vsd/VsdConverter/VsdConverter/fonts/glyphicons-halflings-regular.eot


+ 0 - 0
etc/vsd/VsdConverter/VsdConverter/fonts/glyphicons-halflings-regular.svg


Some files were not shown because too many files changed in this diff