private List <string> InputHostNames(string name) { List <string> ret = new List <string>(); // 1 2 3 4 5 6 7 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 Console.WriteLine(""); Console.WriteLine("Enter at least one hostname that should be matched for: " + name); while (true) { string curr = Common.InputString("Hostname?", null, true); if (!String.IsNullOrEmpty(curr)) { if (ret.Contains(curr)) { continue; } else { ret.Add(curr); } } else { if (ret.Count > 0) { break; } } } return(ret); }
private List <Node> InputNodes(string name) { List <Node> ret = new List <Node>(); // 1 2 3 4 5 6 7 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 Console.WriteLine(""); Console.WriteLine("Enter at lest one node to which requests for " + name + " should be routed."); Console.WriteLine("Each node should have a heartbeat URL which always returns a 200/OK to indicate"); Console.WriteLine("that the node is online."); Console.WriteLine(""); Console.WriteLine("Press ENTER to supply an empty hostname to finish."); Console.WriteLine(""); while (true) { Node curr = new Node(); curr.Hostname = Common.InputString("Hostname?", null, true); if (String.IsNullOrEmpty(curr.Hostname)) { if (ret.Count < 1) { continue; } else { break; } } curr.Port = Common.InputInteger("Port?", 80, true, false); curr.Ssl = Common.InputBoolean("Ssl?", false); curr.HeartbeatUrl = Common.InputString("Heartbeat URL [full URL, i.e. http://host.mydomain.com:80/api/]?", null, false); curr.PollingIntervalMsec = 2500; curr.MaxFailures = 4; ret.Add(curr); } return(ret); }
private List <Host> InputHosts() { Host ret = new Host(); // 1 2 3 4 5 6 7 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 Console.WriteLine(""); Console.WriteLine("The loadbalancer distributes traffic destined to a given 'host' to a 'node'"); Console.WriteLine("mapped to that host. A host can have multiple nodes mapped to it."); Console.WriteLine("Let's define a host that your loadbalancer will monitor."); Console.WriteLine(""); Console.WriteLine("Example:"); Console.WriteLine(""); Console.WriteLine(" Name: Google"); Console.WriteLine(" |"); Console.WriteLine(" |-- Hosts:"); Console.WriteLine(" | |-- google.com"); Console.WriteLine(" | |-- www.google.com"); Console.WriteLine(" |"); Console.WriteLine(" |-- Nodes:"); Console.WriteLine(" |-- server1.mydomain.com"); Console.WriteLine(" |-- server2.mydomain.com"); Console.WriteLine(""); Console.WriteLine("In this example, a request to either google.com or www.google.com would be"); Console.WriteLine("distributed to either server1.mydomain.com or server2.mydomain.com."); Console.WriteLine(""); ret.Name = Common.InputString("What is the name of the site?", "Google", false); ret.HttpHostNames = InputHostNames(ret.Name); ret.Nodes = InputNodes(ret.Name); ret.BalancingScheme = BalancingScheme.RoundRobin; ret.HandlingMode = HandlingMode.Redirect; ret.AcceptInvalidCerts = true; List <Host> retList = new List <Host>(); retList.Add(ret); return(retList); }
private void RunSetup() { #region Variables DateTime timestamp = DateTime.Now; Settings settings = new Settings(); #endregion #region Welcome Console.WriteLine(""); Console.ForegroundColor = ConsoleColor.DarkGray; Console.WriteLine(@" _ _ "); Console.WriteLine(@" | |____ ___ __| |__ __ _ ___ ___ "); Console.WriteLine(@" | / /\ V / '_ \ '_ \/ _` (_-</ -_) "); Console.WriteLine(@" |_\_\ \_/| .__/_.__/\__,_/__/\___| "); Console.WriteLine(@" |_| "); Console.WriteLine(@" "); Console.ResetColor(); Console.WriteLine(""); Console.WriteLine("Kvpbase Storage Server"); Console.WriteLine(""); // 1 2 3 4 5 6 7 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 Console.WriteLine("Thank you for using Kvpbase! We'll put together a basic system configuration"); Console.WriteLine("so you can be up and running quickly. You'll want to modify the System.json"); Console.WriteLine("file after to ensure a more secure operating environment."); #endregion #region Initial-Settings settings.EnableConsole = true; settings.Server = new Settings.SettingsServer(); settings.Server.Port = 8000; settings.Server.DnsHostname = "localhost"; settings.Server.Ssl = false; settings.Server.HeaderApiKey = "x-api-key"; settings.Server.HeaderEmail = "x-email"; settings.Server.HeaderPassword = "******"; settings.Server.MaxObjectSize = 2199023255552; // 2TB object size settings.Server.MaxTransferSize = 536870912; // 512MB transfer size settings.Storage = new Settings.SettingsStorage(); settings.Storage.Directory = "./Storage/"; Directory.CreateDirectory(settings.Storage.Directory); settings.Syslog = new Settings.SettingsSyslog(); settings.Syslog.ConsoleLogging = true; settings.Syslog.Header = "kvpbase"; settings.Syslog.ServerIp = "127.0.0.1"; settings.Syslog.ServerPort = 514; settings.Syslog.LogHttpRequests = false; settings.Syslog.LogHttpResponses = false; settings.Syslog.MinimumLevel = 1; #endregion #region Databases // 1 2 3 4 5 6 7 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 Console.WriteLine(""); Console.WriteLine("Kvpbase requires access to an external database, either Microsoft SQL Server,"); Console.WriteLine("MySQL, or PostgreSQL, for holding configuration-related information. Please"); Console.WriteLine("provide access details for your database. The user account supplied must have"); Console.WriteLine("the ability to CREATE and DROP tables along with issue queries containing"); Console.WriteLine("SELECT, INSERT, UPDATE, and DELETE."); Console.WriteLine(""); Console.WriteLine("IMPORTANT: The database must be created before continuing. Kvpbase will"); Console.WriteLine("automatically create the tables for you."); Console.WriteLine(""); settings.ConfigDatabase = new Settings.SettingsDatabase(); bool dbSet = false; while (!dbSet) { string userInput = Common.InputString("Database type [mssql|mysql|pgsql]:", "mssql", false); switch (userInput) { case "mssql": settings.ConfigDatabase.Type = DatabaseWrapper.DbTypes.MsSql; settings.ConfigDatabase.Hostname = Common.InputString("Hostname:", "localhost", false); settings.ConfigDatabase.Port = Common.InputInteger("Port:", 1433, true, false); settings.ConfigDatabase.Username = Common.InputString("Username:"******"sa", false); settings.ConfigDatabase.Password = Common.InputString("Password:"******"Instance (for SQLEXPRESS):", null, true); settings.ConfigDatabase.DatabaseName = Common.InputString("Database name:", "kvpbaseconfig", false); dbSet = true; break; case "mysql": settings.ConfigDatabase.Type = DatabaseWrapper.DbTypes.MySql; settings.ConfigDatabase.Hostname = Common.InputString("Hostname:", "localhost", false); settings.ConfigDatabase.Port = Common.InputInteger("Port:", 3306, true, false); settings.ConfigDatabase.Username = Common.InputString("Username:"******"root", false); settings.ConfigDatabase.Password = Common.InputString("Password:"******"Schema name:", "kvpbaseconfig", false); dbSet = true; break; case "pgsql": settings.ConfigDatabase.Type = DatabaseWrapper.DbTypes.PgSql; settings.ConfigDatabase.Hostname = Common.InputString("Hostname:", "localhost", false); settings.ConfigDatabase.Port = Common.InputInteger("Port:", 5432, true, false); settings.ConfigDatabase.Username = Common.InputString("Username:"******"postgres", false); settings.ConfigDatabase.Password = Common.InputString("Password:"******"Schema name:", "kvpbaseconfig", false); dbSet = true; break; } } // 1 2 3 4 5 6 7 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 Console.WriteLine(""); Console.WriteLine("Kvpbase also requires database access for storage metadata. This database can"); Console.WriteLine("be the same as your configuration database or different."); Console.WriteLine(""); bool useConfigDatabase = Common.InputBoolean("Use configuration database settings for storage database?", true); if (useConfigDatabase) { settings.StorageDatabase = new Settings.SettingsDatabase(); settings.StorageDatabase.Type = settings.ConfigDatabase.Type; settings.StorageDatabase.Hostname = settings.ConfigDatabase.Hostname; settings.StorageDatabase.Port = settings.ConfigDatabase.Port; settings.StorageDatabase.Username = settings.ConfigDatabase.Username; settings.StorageDatabase.Password = settings.ConfigDatabase.Password; settings.StorageDatabase.InstanceName = settings.ConfigDatabase.InstanceName; settings.StorageDatabase.DatabaseName = Common.InputString("Database name: ", "kvpbasedata", false); } else { dbSet = false; while (!dbSet) { string userInput = Common.InputString("Database type [mssql|mysql|pgsql]:", "mssql", false); switch (userInput) { case "mssql": settings.StorageDatabase.Type = DatabaseWrapper.DbTypes.MsSql; settings.StorageDatabase.Hostname = Common.InputString("Hostname:", "localhost", false); settings.StorageDatabase.Port = Common.InputInteger("Port:", 1433, true, false); settings.StorageDatabase.Username = Common.InputString("Username:"******"sa", false); settings.StorageDatabase.Password = Common.InputString("Password:"******"Instance (for SQLEXPRESS):", null, true); settings.StorageDatabase.DatabaseName = Common.InputString("Database name:", "kvpbaseconfig", false); dbSet = true; break; case "mysql": settings.StorageDatabase.Type = DatabaseWrapper.DbTypes.MySql; settings.StorageDatabase.Hostname = Common.InputString("Hostname:", "localhost", false); settings.StorageDatabase.Port = Common.InputInteger("Port:", 3306, true, false); settings.StorageDatabase.Username = Common.InputString("Username:"******"root", false); settings.StorageDatabase.Password = Common.InputString("Password:"******"Schema name:", "kvpbaseconfig", false); dbSet = true; break; case "pgsql": settings.StorageDatabase.Type = DatabaseWrapper.DbTypes.PgSql; settings.StorageDatabase.Hostname = Common.InputString("Hostname:", "localhost", false); settings.StorageDatabase.Port = Common.InputInteger("Port:", 5432, true, false); settings.StorageDatabase.Username = Common.InputString("Username:"******"postgres", false); settings.StorageDatabase.Password = Common.InputString("Password:"******"Schema name:", "kvpbaseconfig", false); dbSet = true; break; } } } #endregion #region Write-Files-and-Records Console.WriteLine(""); Console.WriteLine("| Writing system.json"); Common.WriteFile("System.json", Encoding.UTF8.GetBytes(Common.SerializeJson(settings, true))); Console.WriteLine("| Initializing logging"); LoggingModule logging = new LoggingModule("127.0.0.1", 514); Console.WriteLine( "| Initializing config DB: " + settings.ConfigDatabase.Hostname + "/" + settings.ConfigDatabase.DatabaseName + " [" + settings.ConfigDatabase.Type.ToString() + "]"); DatabaseClient configDb = new DatabaseClient( settings.ConfigDatabase.Type, settings.ConfigDatabase.Hostname, settings.ConfigDatabase.Port, settings.ConfigDatabase.Username, settings.ConfigDatabase.Password, settings.ConfigDatabase.InstanceName, settings.ConfigDatabase.DatabaseName); Console.WriteLine( "| Initializing storage DB: " + settings.StorageDatabase.Hostname + "/" + settings.StorageDatabase.DatabaseName + " [" + settings.StorageDatabase.Type.ToString() + "]"); DatabaseClient storageDb = new DatabaseClient( settings.StorageDatabase.Type, settings.StorageDatabase.Hostname, settings.StorageDatabase.Port, settings.StorageDatabase.Username, settings.StorageDatabase.Password, settings.StorageDatabase.InstanceName, settings.StorageDatabase.DatabaseName); Console.WriteLine("| Initializing configuration manager"); ConfigManager configMgr = new ConfigManager(settings, logging, configDb); Console.WriteLine("| Adding user [default]"); UserMaster currUser = new UserMaster(); currUser.GUID = "default"; currUser.Email = "*****@*****.**"; currUser.Password = "******"; currUser.Address1 = "123 Some Street"; currUser.Cellphone = "408-555-1212"; currUser.City = "San Jose"; currUser.CompanyName = "Default Company"; currUser.Country = "USA"; currUser.FirstName = "First"; currUser.LastName = "Last"; currUser.PostalCode = "95128"; currUser.State = "CA"; currUser.CreatedUtc = timestamp; currUser.Active = true; configMgr.AddUser(currUser); currUser = configMgr.GetUserByGuid("default"); Console.WriteLine("| Adding API key [default]"); ApiKey currApiKey = new ApiKey(); currApiKey = new ApiKey(); currApiKey.GUID = "default"; currApiKey.Notes = "Created by setup script"; currApiKey.UserMasterId = currUser.Id; currApiKey.Active = true; currApiKey.CreatedUtc = timestamp; configMgr.AddApiKey(currApiKey); currApiKey = configMgr.GetApiKeyByGuid("default"); Console.WriteLine("| Adding permission [default]"); Permission currPerm = new Permission(); currPerm.GUID = "default"; currPerm.DeleteContainer = true; currPerm.DeleteObject = true; currPerm.ReadContainer = true; currPerm.ReadObject = true; currPerm.WriteContainer = true; currPerm.WriteObject = true; currPerm.ApiKeyId = currApiKey.Id; currPerm.Notes = "Created by setup script"; currPerm.UserMasterId = currUser.Id; currPerm.Active = true; currPerm.CreatedUtc = timestamp; configMgr.AddPermission(currPerm); currPerm = configMgr.GetPermissionByGuid("default"); Console.WriteLine("| Creating container [default]"); string htmlFile = SampleHtmlFile("http://github.com/kvpbase"); string textFile = SampleTextFile("http://github.com/kvpbase"); string jsonFile = SampleJsonFile("http://github.com/kvpbase"); ContainerManager containerMgr = new ContainerManager(settings, logging, configMgr, storageDb); Container container = new Container(); container.UserGuid = "default"; container.Name = "default"; container.GUID = "default"; container.ObjectsDirectory = settings.Storage.Directory + container.UserGuid + "/" + container.Name + "/"; container.EnableAuditLogging = true; container.IsPublicRead = true; container.IsPublicWrite = false; containerMgr.Add(container); ContainerClient client = null; containerMgr.GetContainerClient("default", "default", out client); Console.WriteLine("| Writing sample files to container [default]"); ErrorCode error; client.WriteObject("hello.html", "text/html", Encoding.UTF8.GetBytes(htmlFile), null, out error); client.WriteObject("hello.txt", "text/plain", Encoding.UTF8.GetBytes(textFile), null, out error); client.WriteObject("hello.json", "application/json", Encoding.UTF8.GetBytes(jsonFile), null, out error); #endregion #region Wrap-Up // 1 2 3 4 5 6 7 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 Console.WriteLine(""); Console.WriteLine(Common.Line(79, "-")); Console.WriteLine(""); Console.WriteLine("We have created your first user account and permissions."); Console.WriteLine(" Email : " + currUser.Email); Console.WriteLine(" Password : "******" GUID : " + currUser.GUID); Console.WriteLine(" API Key : " + currApiKey.GUID); Console.WriteLine(""); Console.WriteLine("We've also created sample files for you so that you can see your node in"); Console.WriteLine("action. Go to the following URLs in your browser and see what happens!"); Console.WriteLine(""); Console.WriteLine(" http://localhost:8000/"); Console.WriteLine(" http://localhost:8000/default/default?_container&_html"); Console.WriteLine(" http://localhost:8000/default/default/hello.html"); Console.WriteLine(" http://localhost:8000/default/default/hello.html?_metadata=true"); Console.WriteLine(" http://localhost:8000/default/default/hello.txt"); Console.WriteLine(" http://localhost:8000/default/default/hello.json"); Console.WriteLine(""); Console.WriteLine("Kvpbase is set to listen on 'localhost' and will only respond to requests"); Console.WriteLine("from the local machine. SSL is disabled. Modify the System.json file to"); Console.WriteLine("change these settings."); Console.WriteLine(""); #endregion }
private void RunSetup() { #region Variables DateTime ts = DateTime.Now; Settings ret = new Settings(); #endregion #region Welcome Console.WriteLine(""); Console.WriteLine(@" _ _ "); Console.WriteLine(@" | |____ ___ __| |__ __ _ ___ ___ "); Console.WriteLine(@" | / /\ V / '_ \ '_ \/ _` (_-</ -_) "); Console.WriteLine(@" |_\_\ \_/| .__/_.__/\__,_/__/\___| "); Console.WriteLine(@" |_| "); Console.WriteLine(@" "); Console.ResetColor(); Console.WriteLine(""); Console.WriteLine("Kvpbase CryptoServer"); Console.WriteLine(""); // 1 2 3 4 5 6 7 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 Console.WriteLine("Thank you for using kvpbase! We'll put together a basic system configuration"); Console.WriteLine("so you can be up and running quickly."); Console.WriteLine(""); Console.WriteLine("Press ENTER to get started."); Console.WriteLine(""); Console.WriteLine(Common.Line(79, "-")); Console.ReadLine(); #endregion #region Initial-Settings ret.EnableConsole = true; #endregion #region Server ret.Server = new SettingsServer(); ret.Server.Ssl = false; ret.Server.Port = Common.InputInteger("On which TCP port shall this node listen?", 9000, true, false); ret.Server.DnsHostname = Common.InputString("On which hostname shall this node listen?", "localhost", false); Console.WriteLine("This node is configured to use HTTP (not HTTPS) and is accessible at:"); Console.WriteLine(""); Console.WriteLine(" http://" + ret.Server.DnsHostname + ":" + ret.Server.Port); Console.WriteLine(""); Console.WriteLine("Be sure to install an SSL certificate and modify your config file to"); Console.WriteLine("use SSL to maximize security and set the correct hostname."); Console.WriteLine(""); #endregion #region Crypto ret.Crypto = new SettingsCrypto(); // 1 2 3 4 5 6 7 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 Console.WriteLine("Let's configure your encryption material, i.e. the super-secret key"); Console.WriteLine("and other pieces that are used to generate keys that are then used"); Console.WriteLine("to encrypt and decrypt your data."); Console.WriteLine(""); if (Common.InputBoolean("Would you like us to create encryption material for you?", true)) { ret.Crypto.InitVector = Common.RandomHexString(16); Thread.Sleep(10); ret.Crypto.Passphrase = Common.RandomHexString(16); Thread.Sleep(100); ret.Crypto.Salt = Common.RandomHexString(16); } else { while (true) { Console.WriteLine("All of these values should be 16 hexadecimal characters."); Console.WriteLine(" i.e. 0123456789ABCDEF"); ret.Crypto.Passphrase = Common.InputString("Passphrase : ", null, false); ret.Crypto.InitVector = Common.InputString("Initialization Vector : ", null, false); ret.Crypto.Salt = Common.InputString("Salt : ", null, false); if (ret.Crypto.Passphrase.Length != 16 || ret.Crypto.InitVector.Length != 16 || ret.Crypto.Salt.Length != 16) { Console.WriteLine("All values must be 16 characters in length"); continue; } if (!Common.IsHexString(ret.Crypto.Passphrase) || !Common.IsHexString(ret.Crypto.InitVector) || !Common.IsHexString(ret.Crypto.Salt)) { Console.WriteLine("All values must be hexadecimal strings, i.e. 0123456789ABCDEF"); continue; } Console.WriteLine(""); break; } } #endregion #region Auth ret.Auth = new SettingsAuth(); ret.Auth.ApiKeyHeader = "x-api-key"; ret.Auth.AdminApiKey = "admin"; ret.Auth.CryptoApiKey = "user"; #endregion #region Syslog ret.Logging = new SettingsLogging(); ret.Logging.ConsoleLogging = true; ret.Logging.SyslogServerIp = "127.0.0.1"; ret.Logging.SyslogServerPort = 514; ret.Logging.LogRequests = false; ret.Logging.LogResponses = false; ret.Logging.MinimumSeverityLevel = 1; #endregion #region REST ret.Rest = new SettingsRest(); ret.Rest.AcceptInvalidCerts = true; ret.Rest.UseWebProxy = false; ret.Rest.WebProxyUrl = ""; #endregion #region Overwrite-Existing-Config-Files #region System-Config if (Common.FileExists("System.json")) { Console.WriteLine("System configuration file already exists."); if (Common.InputBoolean("Do you wish to overwrite this file?", true)) { Common.DeleteFile("System.json"); if (!Common.WriteFile("System.json", Common.SerializeJson(ret), false)) { Common.ExitApplication("Setup", "Unable to write System.json", -1); return; } } } else { if (!Common.WriteFile("System.json", Common.SerializeJson(ret), false)) { Common.ExitApplication("Setup", "Unable to write System.json", -1); return; } } #endregion #endregion #region Finish Console.WriteLine(""); Console.WriteLine("All finished!"); Console.WriteLine(""); Console.WriteLine("If you ever want to return to this setup wizard, just re-run the application"); Console.WriteLine("from the terminal with the 'setup' argument."); Console.WriteLine(""); Console.WriteLine("Press ENTER to start."); Console.WriteLine(""); Console.ReadLine(); #endregion }
private void RunSetup() { #region Variables DateTime ts = DateTime.Now; Settings ret = new Settings(); #endregion #region Welcome Console.WriteLine(""); Console.WriteLine(@" _ _ "); Console.WriteLine(@" | |____ ___ __| |__ __ _ ___ ___ "); Console.WriteLine(@" | / /\ V / '_ \ '_ \/ _` (_-</ -_) "); Console.WriteLine(@" |_\_\ \_/| .__/_.__/\__,_/__/\___| "); Console.WriteLine(@" |_| "); Console.WriteLine(@" "); Console.ResetColor(); Console.WriteLine(""); Console.WriteLine("Kvpbase LoadBalancer"); Console.WriteLine(""); // 1 2 3 4 5 6 7 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 Console.WriteLine("Thank you for using kvpbase! We'll put together a basic system configuration"); Console.WriteLine("so you can be up and running quickly."); Console.WriteLine(""); Console.WriteLine("Press ENTER to get started."); Console.WriteLine(""); Console.WriteLine(Common.Line(79, "-")); Console.ReadLine(); #endregion #region Initial-Settings ret.EnableConsole = true; ret.RedirectStatusCode = 302; ret.RedirectStatusString = "Moved Temporarily"; #endregion #region Server ret.Server = new SettingsServer(); ret.Server.Ssl = false; ret.Server.Port = Common.InputInteger("On which TCP port shall this node listen?", 9000, true, false); ret.Server.DnsHostname = Common.InputString("On which hostname shall this node listen?", "localhost", false); Console.WriteLine("This node is configured to use HTTP (not HTTPS) and is accessible at:"); Console.WriteLine(""); Console.WriteLine(" http://" + ret.Server.DnsHostname + ":" + ret.Server.Port); Console.WriteLine(""); Console.WriteLine("Be sure to install an SSL certificate and modify your config file to"); Console.WriteLine("use SSL to maximize security and set the correct hostname."); Console.WriteLine(""); #endregion #region Auth ret.Auth = new SettingsAuth(); ret.Auth.AdminApiKeyHeader = "x-api-key"; ret.Auth.AdminApiKey = "admin"; #endregion #region Syslog ret.Logging = new SettingsLogging(); ret.Logging.ConsoleLogging = true; ret.Logging.SyslogServerIp = "127.0.0.1"; ret.Logging.SyslogServerPort = 514; ret.Logging.LogRequests = false; ret.Logging.LogResponses = false; ret.Logging.MinimumSeverityLevel = 1; #endregion #region REST ret.Rest = new SettingsRest(); ret.Rest.AcceptInvalidCerts = true; ret.Rest.UseWebProxy = false; ret.Rest.WebProxyUrl = ""; #endregion #region Hosts ret.Hosts = InputHosts(); #endregion #region Overwrite-Existing-Config-Files #region System-Config if (Common.FileExists("System.json")) { Console.WriteLine("System configuration file already exists."); if (Common.InputBoolean("Do you wish to overwrite this file?", true)) { Common.DeleteFile("System.json"); if (!Common.WriteFile("System.json", Common.SerializeJson(ret), false)) { Common.ExitApplication("Setup", "Unable to write System.json", -1); return; } } } else { if (!Common.WriteFile("System.json", Common.SerializeJson(ret), false)) { Common.ExitApplication("Setup", "Unable to write System.json", -1); return; } } #endregion #endregion #region Finish Console.WriteLine(""); Console.WriteLine("All finished!"); Console.WriteLine(""); Console.WriteLine("If you ever want to return to this setup wizard, just re-run the application"); Console.WriteLine("from the terminal with the 'setup' argument."); Console.WriteLine(""); Console.WriteLine("Press ENTER to start."); Console.WriteLine(""); Console.ReadLine(); #endregion }