/// <summary>
        /// Deploy the application runtime settings.
        /// </summary>
        /// <param name="jsonSettings"></param>
        /// <param name="jsonSettingsArray"></param>
        /// <param name="replacer"></param>
        public void deploySettings(
            string jsonSettings,
            string jsonSettingsArray,
            RuntimeSettingsReplacer replacer)
        {
            // Write the settings in a directory in the application folder itself.
            // When deployed as web app or similar, the other deployers must hide this directory...
            var settingsFile = UtilsSystem.EnsureDirectoryExists(
                Path.Combine(this.Deployment.runtimePath, "chef-settings.json"));

            File.WriteAllText(settingsFile, jsonSettings);

            var settingsFileNested = UtilsSystem.EnsureDirectoryExists(
                Path.Combine(this.Deployment.runtimePath, "chef-settings-nested.json"));

            File.WriteAllText(settingsFileNested, jsonSettingsArray);

            // Why don't we write the settings directly to the AppRoot? Because it might
            // be exposed to the public if the application is mounted as a web application...
            // So we just hint to the location of the runtime, and the application
            // must implement the code needed to load the settings.
            var hintFile = UtilsSystem.EnsureDirectoryExists(
                UtilsSystem.CombinePaths(this.Deployment.appPath, "chef-runtime.path"));

            // We hint to the runtime path, not the specific file
            File.WriteAllText(hintFile, this.Deployment.runtimePath);

            // Dump the configuration files if requested to do so...
            foreach (var kvp in this.GetSettings().configuration_dump_paths ?? new Dictionary <string, string>())
            {
                var destinationDir = UtilsSystem.CombinePaths(this.Deployment.appPath, kvp.Value);
                if (!Directory.Exists(destinationDir))
                {
                    Directory.CreateDirectory(destinationDir);
                }

                var settingsFileDump = UtilsSystem.EnsureDirectoryExists(
                    Path.Combine(destinationDir, "chef-settings.json"));

                File.WriteAllText(settingsFileDump, jsonSettings);

                var settingsFileNestedDump = UtilsSystem.EnsureDirectoryExists(
                    Path.Combine(destinationDir, "chef-settings-nested.json"));

                File.WriteAllText(settingsFileNestedDump, jsonSettingsArray);

                var settingsFileNestedYaml = UtilsSystem.EnsureDirectoryExists(
                    Path.Combine(destinationDir, "chef-settings-nested.yml"));

                File.WriteAllText(settingsFileNestedYaml, UtilsYaml.JsonToYaml(jsonSettingsArray));
            }

            // Now replace the settings in the configuration templates
            foreach (var kvp in this.GetSettings().configuration_replacement_files ?? new Dictionary <string, string>())
            {
                var sourcePath      = UtilsSystem.CombinePaths(this.Deployment.appPath, kvp.Key);
                var destinationPath = UtilsSystem.CombinePaths(this.Deployment.appPath, kvp.Value);

                var contents = File.ReadAllText(sourcePath);

                if (destinationPath == sourcePath)
                {
                    throw new Exception("Destination and source for configuration settings replacements cannot be the same.");
                }

                contents = replacer.DoReplace(contents);

                File.WriteAllText(destinationPath, contents);
            }
        }
        public void TestSettingsReplacer()
        {
            Dictionary <string, string> settings = new Dictionary <string, string>();

            settings["a"] = "this thing has a backslash and needs to be \\ escaped to be used as a json literal";
            settings["b"] = "this thing has a <html> markup that needs ' to be put inside an XML \" placeholder to be & used as a json literal";

            var replacer = new RuntimeSettingsReplacer(settings);

            Assert.Equal("this thing has a backslash and needs to be \\\\ escaped to be used as a json literal", replacer.DoReplace("{@a|filter: jsonescape@}"));
            Assert.Equal("this thing has a backslash and needs to be \\\\ escaped to be used as a json literal", replacer.DoReplace("{@a|filter:jsonescape@}"));

            Assert.Equal("this thing has a backslash and needs to be / escaped to be used as a json literal", replacer.DoReplace("{@a|filter:allforward@}"));

            Assert.Equal("this thing has a &lt;html&gt; markup that needs &apos; to be put inside an XML &quot; placeholder to be &amp; used as a json literal", replacer.DoReplace("{@b|filter:xmlescape@}"));
        }