public override void Invoke(BootstrapSettings settings)
		{
			var localIniFilePath = Path.Combine(settings.CouchDBDirectory.FullName, @"etc\couchdb\local.ini");
			var iniFile = new IniFile(localIniFilePath);

			UpdateDatabaseLocation(iniFile, Path.Combine(settings.DataDirectory.FullName, "couchdb"));
			UpdateLogLocation(iniFile, settings.LogDirectory.FullName);

			if (settings.SetupCouchDBLucene)
			{
				var couchDBLuceneConfigFileFullName = 
					Path.Combine(settings.CouchDBLuceneDirectory.FullName, @"conf\couchdb-lucene.ini");
				var couchdbLuceneIniFile = new IniFile(couchDBLuceneConfigFileFullName);

				// ReSharper disable PossibleInvalidOperationException
				var port = settings.CouchDBLucenePort.Value;
				// ReSharper restore PossibleInvalidOperationException

				UpdateLuceneListeningPort(couchdbLuceneIniFile, port, settings.EndpointToListenOn.ToHttpUri());
				UpdateLuceneLogDirectory(settings.CouchDBLuceneDirectory, settings.LogDirectory.FullName);

				AddCouchDBLuceneHooks(iniFile, settings.CouchDBLuceneDirectory, port);
			}

			UpdateIPSettings(iniFile, settings.EndpointToListenOn);

			UpdateReplicationSettings(iniFile, settings.ReplicationSettings);

			string userName = settings.AdminUserName;
			string plainTextPassword = settings.AdminPlainTextPassword;
			if(userName.HasValue() && plainTextPassword.HasValue())
				AddAdminUser(iniFile, userName, plainTextPassword);
		}
		public override void Invoke(BootstrapSettings settings)
		{
			Extract(settings.CouchDBDistributive, settings.CouchDBDirectory);
			if (settings.SetupCouchDBLucene)
			{
				Extract(settings.CouchDBLuceneDistributive, settings.CouchDBLuceneDirectory);
				Extract(settings.JavaDistributive, settings.JavaDirectory);
			}
		}
		/// <constructor />
		public CouchDBWatchdog(BootstrapSettings settings)
		{
			this.settings = settings;
			if (!settings.BinDirectory.Exists)
				throw new Exception("CouchDB folder does not exist");

			startCouchDbBatchFile = settings.BinDirectory.EnumerateFiles("couchdb.bat", SearchOption.AllDirectories).First();
			couchDbBinFolder = startCouchDbBatchFile.Directory;
		}
		/// <summary>Initializes, sets up and runs CouchDB (+couchdb-lucene) instance.</summary>
		public static CouchDBWatchdog Bootstrap(BootstrapSettings settings)
		{
			settings.Lock();

			RunStartupTasks(settings);
			var watchdog = new CouchDBWatchdog(settings);
			watchdog.Start();
			CouchDBReplicator.UpdateReplicationState(
				new IPEndPoint(IPAddress.Loopback, settings.EndpointToListenOn.Port), 
				settings.ReplicationSettings
			);
			return watchdog;
		}
		private static void ExecuteTaskRecursively(
			IStartupTask task, ISet<Type> executedTasks, BootstrapSettings settings)
		{
			var dependencies =
				from dependencyType in task.Dependencies
				where !executedTasks.Contains(dependencyType)
				select (IStartupTask) Activator.CreateInstance(dependencyType);

			foreach (var dependencyTask in dependencies)
				ExecuteTaskRecursively(dependencyTask, executedTasks, settings);

			Log.InfoFormat("Executing {0} startup task", task.Name);
			task.Invoke(settings);
			Log.InfoFormat("{0} startup task have executed successfully", task.Name);
			executedTasks.Add(task.GetType());
		}
		public override void Invoke(BootstrapSettings settings)
		{
			if (!settings.SetupCouchDBLucene) return;

			var luceneRunScript = new FileInfo(Path.Combine(settings.CouchDBLuceneDirectory.FullName, @"bin\run.bat"));

			if(!luceneRunScript.Exists)
				throw new InvalidOperationException("couchdb-lucene run script missing. Expected to be at: " + luceneRunScript.FullName);

			var javaExecutable = new FileInfo(Path.Combine(settings.JavaDirectory.FullName, @"bin\java.exe"));
			if(!javaExecutable.Exists)
				throw new InvalidOperationException("java.exe missing. Expected to be at: " + javaExecutable.FullName);
			
			var originalContent = File.ReadAllText(luceneRunScript.FullName);
			var edititedContent = originalContent.Replace("java.exe", string.Format("\"{0}\"", javaExecutable.FullName));
			File.WriteAllText(luceneRunScript.FullName, edititedContent, Encoding.Default);
		}
		public virtual void Invoke(BootstrapSettings settings) { }
		private static void RunStartupTasks(BootstrapSettings settings)
		{
			ExecuteTaskRecursively(Activator.CreateInstance<RootTask>(), new HashSet<Type>(), settings);
		}