Winify – Diff between revs 29 and 30

Subversion Repositories:
Rev:
Only display areas with differencesIgnore whitespace
Rev 29 Rev 30
1 using System; 1 using System;
2 using System.Collections.Concurrent; 2 using System.Collections.Concurrent;
3 using System.ComponentModel; 3 using System.ComponentModel;
4 using System.Configuration; -  
5 using System.Diagnostics; 4 using System.Drawing;
6 using System.IO; 5 using System.IO;
-   6 using System.Reflection;
7 using System.Text; 7 using System.Text;
8 using System.Threading; 8 using System.Threading;
9 using System.Threading.Tasks; 9 using System.Threading.Tasks;
10 using System.Windows.Forms; 10 using System.Windows.Forms;
-   11 using NetSparkleUpdater;
11 using AutoUpdaterDotNET; 12 using NetSparkleUpdater.Enums;
-   13 using NetSparkleUpdater.SignatureVerifiers;
-   14 using NetSparkleUpdater.UI.WinForms;
12 using Serilog; 15 using Serilog;
13 using Servers; 16 using Servers;
14 using Toasts; 17 using Toasts;
15 using Winify.Gotify; 18 using Winify.Gotify;
16 using Winify.Servers.Serialization; -  
17 using Winify.Settings; 19 using Winify.Settings;
18 using Winify.Utilities; 20 using Winify.Utilities;
-   21 using Winify.Utilities.Serialization;
19   22  
20 namespace Winify 23 namespace Winify
21 { 24 {
22 public partial class Form1 : Form 25 public partial class MainForm : Form
23 { 26 {
24 #region Private Delegates, Events, Enums, Properties, Indexers and Fields 27 #region Public Enums, Properties and Fields
-   28  
-   29 public Configuration.Configuration Configuration { get; set; }
-   30  
-   31 public ScheduledContinuation ChangedConfigurationContinuation { get; set; }
-   32  
-   33 #endregion
25   34  
26 private readonly TaskScheduler _uiTaskScheduler; 35 #region Private Delegates, Events, Enums, Properties, Indexers and Fields
27   36  
28 private AboutForm _aboutForm; 37 private AboutForm _aboutForm;
29   38  
30 private ConcurrentBag<GotifyConnection> _gotifyConnections; 39 private ConcurrentBag<GotifyConnection> _gotifyConnections;
31   40  
32 private SettingsForm _settingsForm; 41 private SettingsForm _settingsForm;
-   42  
-   43 private readonly SparkleUpdater _sparkle;
-   44  
-   45 private readonly CancellationTokenSource _cancellationTokenSource;
-   46  
-   47 private readonly CancellationToken _cancellationToken;
33   48  
34 #endregion 49 #endregion
35   50  
36 #region Constructors, Destructors and Finalizers 51 #region Constructors, Destructors and Finalizers
-   52  
-   53 public MainForm()
-   54 {
-   55 _cancellationTokenSource = new CancellationTokenSource();
-   56 _cancellationToken = _cancellationTokenSource.Token;
-   57  
-   58 ChangedConfigurationContinuation = new ScheduledContinuation();
-   59 }
37   60  
38 public Form1(Mutex mutex) 61 public MainForm(Mutex mutex) : this()
39 { 62 {
40 InitializeComponent(); 63 InitializeComponent();
41   64  
42 Log.Logger = new LoggerConfiguration() 65 Log.Logger = new LoggerConfiguration()
43 .MinimumLevel.Debug() 66 .MinimumLevel.Debug()
44 .WriteTo.File(Path.Combine(Constants.UserApplicationDirectory, "Logs", $"{Constants.AssemblyName}.log"), 67 .WriteTo.File(Path.Combine(Constants.UserApplicationDirectory, "Logs", $"{Constants.AssemblyName}.log"),
45 rollingInterval: RollingInterval.Day) 68 rollingInterval: RollingInterval.Day)
46 .CreateLogger(); 69 .CreateLogger();
47   70  
48 // Upgrade settings if required. 71 // Start application update.
49 if (!ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal).HasFile) -  
50 if (Properties.Settings.Default.UpdateRequired) -  
51 { -  
52 Properties.Settings.Default.Upgrade(); -  
53 Properties.Settings.Default.Reload(); -  
54   -  
55 Properties.Settings.Default.UpdateRequired = false; -  
56 Properties.Settings.Default.Save(); -  
57   -  
58 mutex.ReleaseMutex(); 72 var manifestModuleName = Assembly.GetEntryAssembly().ManifestModule.FullyQualifiedName;
59 Process.Start(Application.ExecutablePath); -  
60 Environment.Exit(0); -  
61 } -  
62   -  
63 // Bind to settings changed event. -  
64 Properties.Settings.Default.SettingsLoaded += Default_SettingsLoaded; -  
65 Properties.Settings.Default.SettingsSaving += Default_SettingsSaving; -  
66 Properties.Settings.Default.PropertyChanged += Default_PropertyChanged; -  
67   -  
68 // Store UI thread context. -  
69 _uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 73 var icon = Icon.ExtractAssociatedIcon(manifestModuleName);
-   74  
70   75 _sparkle = new SparkleUpdater("https://winify.grimore.org/update/appcast.xml",
71 LoadServers().ContinueWith(async task => 76 new Ed25519Checker(SecurityMode.Strict, "LonrgxVjSF0GnY4hzwlRJnLkaxnDn2ikdmOifILzLJY="))
72 { -  
73 var restoredServers = await task; -  
74   -  
75 _gotifyConnections = new ConcurrentBag<GotifyConnection>(); -  
76   -  
77 foreach (var server in restoredServers.Server) -  
78 { -  
79 var gotifyConnection = new GotifyConnection(server); 77 {
80 gotifyConnection.GotifyNotification += GotifyConnection_GotifyNotification; -  
81 gotifyConnection.Start(); -  
82 _gotifyConnections.Add(gotifyConnection); 78 UIFactory = new UIFactory(icon),
83 } -  
84 }); 79 RelaunchAfterUpdate = true
85   -  
86 // Start application update. 80 };
87 AutoUpdater.Start("http://winify.grimore.org/update/winify.xml"); 81 _sparkle.StartLoop(true, true);
88 } 82 }
89   83  
90 /// <summary> 84 /// <summary>
91 /// Clean up any resources being used. 85 /// Clean up any resources being used.
92 /// </summary> 86 /// </summary>
93 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> 87 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
94 protected override void Dispose(bool disposing) 88 protected override void Dispose(bool disposing)
95 { 89 {
96 if (disposing && components != null) 90 if (disposing && components != null) components.Dispose();
97 { -  
98 Properties.Settings.Default.SettingsLoaded -= Default_SettingsLoaded; -  
99 Properties.Settings.Default.SettingsSaving -= Default_SettingsSaving; -  
100 Properties.Settings.Default.PropertyChanged -= Default_PropertyChanged; -  
101   -  
102 components.Dispose(); -  
103 } -  
104   91  
105 base.Dispose(disposing); 92 base.Dispose(disposing);
106 } 93 }
107   94  
108 #endregion 95 #endregion
109   96  
110 #region Event Handlers 97 #region Event Handlers
111   98  
112 private static void Default_PropertyChanged(object sender, PropertyChangedEventArgs e) 99 private async void MainForm_Load(object sender, EventArgs e)
113 { 100 {
114 Properties.Settings.Default.Save(); -  
-   101 Configuration = await LoadConfiguration();
115 } 102  
-   103 var servers = await LoadServers();
116   104 _gotifyConnections = new ConcurrentBag<GotifyConnection>();
-   105 foreach (var server in servers.Server)
-   106 {
117 private static void Default_SettingsSaving(object sender, CancelEventArgs e) 107 var gotifyConnection = new GotifyConnection(server);
118 { -  
119 } 108 gotifyConnection.GotifyNotification += GotifyConnection_GotifyNotification;
120   109 gotifyConnection.Start();
121 private static void Default_SettingsLoaded(object sender, SettingsLoadedEventArgs e) 110 _gotifyConnections.Add(gotifyConnection);
122 { 111 }
123 } 112 }
124   113  
125 private async void SettingsToolStripMenuItem_Click(object sender, EventArgs e) 114 private async void SettingsToolStripMenuItem_Click(object sender, EventArgs e)
126 { 115 {
127 if (_settingsForm != null) return; 116 if (_settingsForm == null)
128   117 {
129 var servers = await LoadServers(); 118 var servers = await LoadServers();
130 var announcements = await LoadAnnouncements(); 119 var announcements = await LoadAnnouncements();
131   120  
132 _settingsForm = new SettingsForm(servers, announcements); 121 _settingsForm = new SettingsForm(this, servers, announcements, _cancellationToken);
133 _settingsForm.Save += SettingsForm_Save; 122 _settingsForm.Save += SettingsForm_Save;
134 _settingsForm.Closing += SettingsForm_Closing; 123 _settingsForm.Closing += SettingsForm_Closing;
-   124 _settingsForm.Show();
135 _settingsForm.Show(); 125 }
136 } 126 }
137   127  
138 private async void SettingsForm_Save(object sender, SettingsSavedEventArgs e) 128 private async void SettingsForm_Save(object sender, SettingsSavedEventArgs e)
139 { 129 {
140 // Save the servers. 130 // Save the servers.
141 await Task.WhenAll(SaveServers(e.Servers), SaveAnnouncements(e.Announcements)); 131 await Task.WhenAll(SaveServers(e.Servers), SaveAnnouncements(e.Announcements));
142   132  
143 // Update connections to gotify servers. 133 // Update connections to gotify servers.
144 while (_gotifyConnections.TryTake(out var gotifyConnection)) 134 while (_gotifyConnections.TryTake(out var gotifyConnection))
145 { 135 {
146 gotifyConnection.GotifyNotification -= GotifyConnection_GotifyNotification; 136 gotifyConnection.GotifyNotification -= GotifyConnection_GotifyNotification;
147 gotifyConnection.Stop(); 137 gotifyConnection.Stop();
148 gotifyConnection.Dispose(); 138 gotifyConnection.Dispose();
149 gotifyConnection = null; 139 gotifyConnection = null;
150 } 140 }
151   141  
152 foreach (var server in e.Servers.Server) 142 foreach (var server in e.Servers.Server)
153 { 143 {
154 var gotifyConnection = new GotifyConnection(server); 144 var gotifyConnection = new GotifyConnection(server);
155 gotifyConnection.GotifyNotification += GotifyConnection_GotifyNotification; 145 gotifyConnection.GotifyNotification += GotifyConnection_GotifyNotification;
156 gotifyConnection.Start(); 146 gotifyConnection.Start();
157 _gotifyConnections.Add(gotifyConnection); 147 _gotifyConnections.Add(gotifyConnection);
158 } 148 }
159 } 149 }
160   150  
161 private void GotifyConnection_GotifyNotification(object sender, GotifyNotificationEventArgs e) 151 private async void GotifyConnection_GotifyNotification(object sender, GotifyNotificationEventArgs e)
162 { -  
163 Task.Factory.StartNew(async () => -  
164 { 152 {
165 var announcements = await LoadAnnouncements(); 153 var announcements = await LoadAnnouncements();
166   154  
167 foreach (var announcement in announcements.Announcement) 155 foreach (var announcement in announcements.Announcement)
168 if (announcement.AppId == e.Notification.AppId) 156 if (announcement.AppId == e.Notification.AppId)
169 { 157 {
170 var configuredNotification = new ToastForm( 158 var configuredNotification = new ToastForm(
171 $"{e.Notification.Title} ({e.Notification.Server.Name}/{e.Notification.AppId})", 159 $"{e.Notification.Title} ({e.Notification.Server.Name}/{e.Notification.AppId})",
172 e.Notification.Message, announcement.LingerTime, e.Image); 160 e.Notification.Message, announcement.LingerTime, e.Image);
173   161  
174 configuredNotification.Show(); 162 configuredNotification.Show();
175   163  
176 return; 164 return;
177 } 165 }
178   -  
179 var notification = new ToastForm( 166  
180 $"{e.Notification.Title} ({e.Notification.Server.Name}/{e.Notification.AppId})", 167 var notification = new ToastForm(
181 e.Notification.Message, 5000, e.Image); 168 $"{e.Notification.Title} ({e.Notification.Server.Name}/{e.Notification.AppId})",
182   169 e.Notification.Message, 5000, e.Image);
183 notification.Show(); 170  
184 }, CancellationToken.None, TaskCreationOptions.LongRunning, _uiTaskScheduler); 171 notification.Show();
185 } 172 }
186   173  
187 private void SettingsForm_Closing(object sender, CancelEventArgs e) 174 private void SettingsForm_Closing(object sender, CancelEventArgs e)
188 { 175 {
189 if (_settingsForm == null) return; 176 if (_settingsForm == null) return;
190   177  
191 _settingsForm.Save -= SettingsForm_Save; 178 _settingsForm.Save -= SettingsForm_Save;
192 _settingsForm.Closing -= SettingsForm_Closing; 179 _settingsForm.Closing -= SettingsForm_Closing;
193 _settingsForm.Dispose(); 180 _settingsForm.Dispose();
194 _settingsForm = null; 181 _settingsForm = null;
195 } 182 }
196   183  
197 private void AboutToolStripMenuItem_Click(object sender, EventArgs e) 184 private void AboutToolStripMenuItem_Click(object sender, EventArgs e)
198 { 185 {
199 if (_aboutForm != null) return; 186 if (_aboutForm != null) return;
200   187  
201 _aboutForm = new AboutForm(); 188 _aboutForm = new AboutForm();
202 _aboutForm.Closing += AboutForm_Closing; 189 _aboutForm.Closing += AboutForm_Closing;
203 _aboutForm.Show(); 190 _aboutForm.Show();
204 } 191 }
205   192  
206 private void AboutForm_Closing(object sender, CancelEventArgs e) 193 private void AboutForm_Closing(object sender, CancelEventArgs e)
207 { 194 {
208 if (_aboutForm == null) return; 195 if (_aboutForm == null) return;
209   196  
210 _aboutForm.Closing -= AboutForm_Closing; 197 _aboutForm.Closing -= AboutForm_Closing;
211 _aboutForm.Dispose(); 198 _aboutForm.Dispose();
212 _aboutForm = null; 199 _aboutForm = null;
213 } 200 }
214   201  
215 private void QuitToolStripMenuItem_Click(object sender, EventArgs e) 202 private void QuitToolStripMenuItem_Click(object sender, EventArgs e)
216 { 203 {
217 Close(); 204 Close();
-   205 }
-   206  
-   207 private async void UpdateToolStripMenuItem_Click(object sender, EventArgs e)
-   208 {
-   209 // Manually check for updates, this will not show a ui
-   210 var result = await _sparkle.CheckForUpdatesQuietly();
-   211 if (result.Status == UpdateStatus.UpdateAvailable)
-   212 {
-   213 // if update(s) are found, then we have to trigger the UI to show it gracefully
-   214 _sparkle.ShowUpdateNeededUI();
-   215 return;
-   216 }
-   217  
-   218 MessageBox.Show("No updates available at this time.", "Horizon", MessageBoxButtons.OK,
-   219 MessageBoxIcon.Asterisk,
-   220 MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly, false);
-   221 }
-   222  
-   223 #endregion
-   224  
-   225 #region Public Methods
-   226  
-   227 public async Task SaveConfiguration()
-   228 {
-   229 if (!Directory.Exists(Constants.UserApplicationDirectory))
-   230 Directory.CreateDirectory(Constants.UserApplicationDirectory);
-   231  
-   232 switch (await Serialization.Serialize(Configuration, Constants.ConfigurationFile, "Configuration",
-   233 "<!ATTLIST Configuration xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>",
-   234 CancellationToken.None))
-   235 {
-   236 case SerializationSuccess<Configuration.Configuration> _:
-   237 Log.Information("Serialized configuration.");
-   238 break;
-   239 case SerializationFailure serializationFailure:
218   240 Log.Warning(serializationFailure.Exception.Message, "Failed to serialize configuration.");
-   241 break;
219 Environment.Exit(0); 242 }
220 } 243 }
221   244  
-   245 public static async Task<Configuration.Configuration> LoadConfiguration()
222 private void UpdateToolStripMenuItem_Click(object sender, EventArgs e) 246 {
-   247 if (!Directory.Exists(Constants.UserApplicationDirectory))
-   248 Directory.CreateDirectory(Constants.UserApplicationDirectory);
-   249  
-   250 var deserializationResult =
-   251 await Serialization.Deserialize<Configuration.Configuration>(Constants.ConfigurationFile,
-   252 Constants.ConfigurationNamespace, Constants.ConfigurationXsd, CancellationToken.None);
-   253  
-   254 switch (deserializationResult)
-   255 {
-   256 case SerializationSuccess<Configuration.Configuration> serializationSuccess:
-   257 return serializationSuccess.Result;
-   258 case SerializationFailure serializationFailure:
-   259 Log.Warning(serializationFailure.Exception, "Failed to load configuration.");
-   260 return new Configuration.Configuration();
-   261 default:
223 { 262 return new Configuration.Configuration();
224 AutoUpdater.Start("http://winify.grimore.org/update/winify.xml"); 263 }
225 } 264 }
226   265  
227 #endregion 266 #endregion
228   267  
229 #region Private Methods 268 #region Private Methods
230   269  
231 private static async Task SaveAnnouncements(Announcements.Announcements announcements) 270 private static async Task SaveAnnouncements(Announcements.Announcements announcements)
232 { 271 {
233 switch (await ServersSerialization.Serialize(announcements, Constants.AnnouncementsFile, "Announcements", 272 switch (await Serialization.Serialize(announcements, Constants.AnnouncementsFile, "Announcements",
234 "<!ATTLIST Announcements xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>")) 273 "<!ATTLIST Announcements xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>",
-   274 CancellationToken.None))
235 { 275 {
236 case SerializationFailure serializationFailure: 276 case SerializationFailure serializationFailure:
237 Log.Warning(serializationFailure.Exception, "Unable to serialize announcements."); 277 Log.Warning(serializationFailure.Exception, "Unable to serialize announcements.");
238 break; 278 break;
239 } 279 }
240 } 280 }
241   281  
242 private static async Task SaveServers(global::Servers.Servers servers) 282 private static async Task SaveServers(Servers.Servers servers)
243 { 283 {
244 // Encrypt password for all servers. 284 // Encrypt password for all servers.
245 var deviceId = Miscellaneous.GetMachineGuid(); 285 var deviceId = Miscellaneous.GetMachineGuid();
246 var @protected = new global::Servers.Servers 286 var @protected = new Servers.Servers
247 { 287 {
248 Server = new BindingListWithCollectionChanged<Server>() 288 Server = new BindingListWithCollectionChanged<Server>()
249 }; 289 };
250 foreach (var server in servers.Server) 290 foreach (var server in servers.Server)
251 { 291 {
252 var encrypted = AES.Encrypt(Encoding.UTF8.GetBytes(server.Password), deviceId); 292 var encrypted = AES.Encrypt(Encoding.UTF8.GetBytes(server.Password), deviceId);
253 var armored = Convert.ToBase64String(encrypted); 293 var armored = Convert.ToBase64String(encrypted);
254   294  
255 @protected.Server.Add(new Server(server.Name, server.Url, server.Username, armored)); 295 @protected.Server.Add(new Server(server.Name, server.Url, server.Username, armored));
256 } 296 }
257   297  
258 switch (await ServersSerialization.Serialize(@protected, Constants.ServersFile, "Servers", 298 switch (await Serialization.Serialize(@protected, Constants.ServersFile, "Servers",
-   299 "<!ATTLIST Servers xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>",
259 "<!ATTLIST Servers xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>")) 300 CancellationToken.None))
260 { 301 {
261 case SerializationFailure serializationFailure: 302 case SerializationFailure serializationFailure:
262 Log.Warning(serializationFailure.Exception, "Unable to serialize servers."); 303 Log.Warning(serializationFailure.Exception, "Unable to serialize servers.");
263 break; 304 break;
264 } 305 }
265 } 306 }
266   307  
267 private static async Task<Announcements.Announcements> LoadAnnouncements() 308 private static async Task<Announcements.Announcements> LoadAnnouncements()
268 { 309 {
269 if (!Directory.Exists(Constants.UserApplicationDirectory)) 310 if (!Directory.Exists(Constants.UserApplicationDirectory))
270 Directory.CreateDirectory(Constants.UserApplicationDirectory); 311 Directory.CreateDirectory(Constants.UserApplicationDirectory);
271   312  
272 var deserializationResult = 313 var deserializationResult =
273 await ServersSerialization.Deserialize<Announcements.Announcements>(Constants.AnnouncementsFile, 314 await Serialization.Deserialize<Announcements.Announcements>(Constants.AnnouncementsFile,
274 "urn:winify-announcements-schema", "Announcements.xsd"); 315 "urn:winify-announcements-schema", "Announcements.xsd", CancellationToken.None);
275   316  
276 switch (deserializationResult) 317 switch (deserializationResult)
277 { 318 {
278 case SerializationSuccess<Announcements.Announcements> serializationSuccess: 319 case SerializationSuccess<Announcements.Announcements> serializationSuccess:
279 return serializationSuccess.Result; 320 return serializationSuccess.Result;
280 case SerializationFailure serializationFailure: 321 case SerializationFailure serializationFailure:
281 Log.Warning(serializationFailure.Exception, "Unable to load announcements."); 322 Log.Warning(serializationFailure.Exception, "Unable to load announcements.");
282 return new Announcements.Announcements(); 323 return new Announcements.Announcements();
283 default: 324 default:
284 return new Announcements.Announcements(); 325 return new Announcements.Announcements();
285 } 326 }
286 } 327 }
287   328  
288 private static async Task<global::Servers.Servers> LoadServers() 329 private static async Task<Servers.Servers> LoadServers()
289 { 330 {
290 if (!Directory.Exists(Constants.UserApplicationDirectory)) 331 if (!Directory.Exists(Constants.UserApplicationDirectory))
291 Directory.CreateDirectory(Constants.UserApplicationDirectory); 332 Directory.CreateDirectory(Constants.UserApplicationDirectory);
292   333  
293 var deserializationResult = 334 var deserializationResult =
294 await ServersSerialization.Deserialize<global::Servers.Servers>(Constants.ServersFile, 335 await Serialization.Deserialize<Servers.Servers>(Constants.ServersFile,
295 "urn:winify-servers-schema", "Servers.xsd"); 336 "urn:winify-servers-schema", "Servers.xsd", CancellationToken.None);
296   337  
297 switch (deserializationResult) 338 switch (deserializationResult)
298 { 339 {
299 case SerializationSuccess<global::Servers.Servers> serializationSuccess: 340 case SerializationSuccess<Servers.Servers> serializationSuccess:
300 // Decrypt password. 341 // Decrypt password.
301 var deviceId = Miscellaneous.GetMachineGuid(); 342 var deviceId = Miscellaneous.GetMachineGuid();
302 var @protected = new global::Servers.Servers 343 var @protected = new Servers.Servers
303 { 344 {
304 Server = new BindingListWithCollectionChanged<Server>() 345 Server = new BindingListWithCollectionChanged<Server>()
305 }; 346 };
306 foreach (var server in serializationSuccess.Result.Server) 347 foreach (var server in serializationSuccess.Result.Server)
307 { 348 {
308 var unarmored = Convert.FromBase64String(server.Password); 349 var unarmored = Convert.FromBase64String(server.Password);
309 var decrypted = Encoding.UTF8.GetString(AES.Decrypt(unarmored, deviceId)); 350 var decrypted = Encoding.UTF8.GetString(AES.Decrypt(unarmored, deviceId));
310   351  
311 @protected.Server.Add(new Server(server.Name, server.Url, server.Username, decrypted)); 352 @protected.Server.Add(new Server(server.Name, server.Url, server.Username, decrypted));
312 } 353 }
313   354  
314 return @protected; 355 return @protected;
315   356  
316 case SerializationFailure serializationFailure: 357 case SerializationFailure serializationFailure:
317 Log.Warning(serializationFailure.Exception, "Unable to load servers."); 358 Log.Warning(serializationFailure.Exception, "Unable to load servers.");
318 return new global::Servers.Servers(); 359 return new Servers.Servers();
319   360  
320 default: 361 default:
321 return new global::Servers.Servers(); 362 return new Servers.Servers();
322 } 363 }
323 } 364 }
324   365  
325 #endregion 366 #endregion
326 } 367 }
327 } 368 }
328   369  
329
Generated by GNU Enscript 1.6.5.90.
370
Generated by GNU Enscript 1.6.5.90.
330   371  
331   372  
332   373