static bool BuildBlueprintUdn(string JsonDir, string UdnDir, string SitemapDir, string ArchivePath, string SitemapArchivePath, BuildActions ExecActions)
		{
			string ApiDir = Path.Combine(UdnDir, "BlueprintAPI");
			if ((ExecActions & BuildActions.Clean) != 0)
			{
				Console.WriteLine("Cleaning '{0}'", ApiDir);
				Utility.SafeDeleteDirectoryContents(ApiDir, true);
				Utility.SafeDeleteDirectoryContents(SitemapDir, true);
			}
			if ((ExecActions & BuildActions.Build) != 0)
			{
				Directory.CreateDirectory(ApiDir);
				Directory.CreateDirectory(SitemapDir);

				// Read the input json file
				string JsonFilePath = Path.Combine(JsonDir, "BlueprintAPI.json");
				var json = (Dictionary<string, object>)fastJSON.JSON.Instance.Parse(File.ReadAllText(JsonFilePath));

				APICategory.LoadTooltips((Dictionary<string, object>)json["Categories"]);

				// TODO: This path is clearly sketchy as hell, but we'll clean it up later maybe
				var Actions = (Dictionary<string, object>)((Dictionary<string, object>)((Dictionary<string, object>)((Dictionary<string, object>)json["Actor"])["Palette"])["ActionSet"])["Actions"];

				APICategory RootCategory = new APICategory(null, "BlueprintAPI", true);

				foreach (var Action in Actions)
				{
					var CategoryList = Action.Key.Split('|');
					var ActionCategory = RootCategory;

					Debug.Assert(CategoryList.Length > 0);
					Debug.Assert(CategoryList[0] == "Library");

					for (int CategoryIndex = 1; CategoryIndex < CategoryList.Length - 1; ++CategoryIndex)
					{
						ActionCategory = ActionCategory.GetSubCategory(CategoryList[CategoryIndex]);
					}

					ActionCategory.AddAction(new APIAction(ActionCategory, CategoryList.Last(), (Dictionary<string, object>)Action.Value));
				}

				// Build a list of pages to output
				List<APIPage> OutputPages = new List<APIPage>(RootCategory.GatherPages().OrderBy(x => x.LinkPath));

				// Create the output directory
				Utility.SafeCreateDirectory(UdnDir);
				Utility.SafeCreateDirectory(Path.Combine(UdnDir, APIFolder));

				// Build the manifest
				Console.WriteLine("Writing manifest...");
				UdnManifest Manifest = new UdnManifest(RootCategory);
				Manifest.PrintConflicts();
				Manifest.Write(Path.Combine(UdnDir, BlueprintAPIFolder + "\\API.manifest"));

				Console.WriteLine("Categories: " + OutputPages.Count(page => page is APICategory));
				Console.WriteLine("Actions: " + OutputPages.Count(page => page is APIAction));

				// Write all the pages
				using (Tracker UdnTracker = new Tracker("Writing UDN pages...", OutputPages.Count))
				{
					foreach (int Idx in UdnTracker.Indices)
					{
						APIPage Page = OutputPages[Idx];

						// Create the output directory
						string MemberDirectory = Path.Combine(UdnDir, Page.LinkPath);
						if (!Directory.Exists(MemberDirectory))
						{
							Directory.CreateDirectory(MemberDirectory);
						}

						// Write the page
						Page.WritePage(Manifest, Path.Combine(MemberDirectory, "index.INT.udn"));
					}
				}

				// Write the sitemap contents
				Console.WriteLine("Writing sitemap contents...");
				RootCategory.WriteSitemapContents(Path.Combine(SitemapDir, "BlueprintAPI.hhc"));

				// Write the sitemap index
				Console.WriteLine("Writing sitemap index...");
				RootCategory.WriteSitemapIndex(Path.Combine(SitemapDir, "BlueprintAPI.hhk"));
			}
			if ((ExecActions & BuildActions.Archive) != 0)
			{
				Console.WriteLine("Creating archive '{0}'", ArchivePath);
				Utility.CreateTgzFromDir(ArchivePath, ApiDir);

				Console.WriteLine("Creating archive '{0}'", SitemapArchivePath);
				Utility.CreateTgzFromDir(SitemapArchivePath, SitemapDir);
			}
			return true;
		}