diff --git a/BodyshopUploader/App.config b/BodyshopUploader/App.config
index 56efbc7..f5e0f5a 100644
--- a/BodyshopUploader/App.config
+++ b/BodyshopUploader/App.config
@@ -1,6 +1,26 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/BodyshopUploader/App.xaml b/BodyshopUploader/App.xaml
index 66b9cb7..a1b0cb1 100644
--- a/BodyshopUploader/App.xaml
+++ b/BodyshopUploader/App.xaml
@@ -2,8 +2,16 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BodyshopUploader"
+ ShutdownMode="OnExplicitShutdown"
StartupUri="Views\Login.xaml">
-
+
+
+
+
+
+
+
+
diff --git a/BodyshopUploader/BodyshopUploader.csproj b/BodyshopUploader/BodyshopUploader.csproj
index 7b7d84c..7c0cb35 100644
--- a/BodyshopUploader/BodyshopUploader.csproj
+++ b/BodyshopUploader/BodyshopUploader.csproj
@@ -29,6 +29,8 @@
false
false
true
+
+
AnyCPU
@@ -53,9 +55,23 @@
favicon.ico
+
+ ..\packages\FirebaseAuthentication.net.3.4.0\lib\netstandard1.1\Firebase.Auth.dll
+
..\packages\Hardcodet.NotifyIcon.Wpf.1.0.8\lib\net451\Hardcodet.Wpf.TaskbarNotification.dll
+
+ ..\packages\MaterialDesignColors.1.2.2\lib\net45\MaterialDesignColors.dll
+
+
+ ..\packages\MaterialDesignThemes.3.0.1\lib\net45\MaterialDesignThemes.Wpf.dll
+
+
+ ..\packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll
+ True
+ True
+
..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll
@@ -63,21 +79,145 @@
..\packages\NLog.4.6.8\lib\net45\NLog.dll
+
+ ..\packages\System.AppContext.4.3.0\lib\net463\System.AppContext.dll
+ True
+ True
+
+
+
+ ..\packages\System.Console.4.3.0\lib\net46\System.Console.dll
+ True
+ True
+
-
+
+ ..\packages\System.Diagnostics.DiagnosticSource.4.3.0\lib\net46\System.Diagnostics.DiagnosticSource.dll
+
+
+ ..\packages\System.Diagnostics.Tracing.4.3.0\lib\net462\System.Diagnostics.Tracing.dll
+ True
+ True
+
+
+ ..\packages\System.Globalization.Calendars.4.3.0\lib\net46\System.Globalization.Calendars.dll
+ True
+ True
+
+
+ ..\packages\System.IO.4.3.0\lib\net462\System.IO.dll
+ True
+ True
+
+
+ ..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll
+ True
+ True
+
+
+
+ ..\packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll
+ True
+ True
+
+
+ ..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll
+ True
+ True
+
+
+ ..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll
+ True
+ True
+
+
+ ..\packages\System.Linq.4.3.0\lib\net463\System.Linq.dll
+ True
+ True
+
+
+ ..\packages\System.Linq.Expressions.4.3.0\lib\net463\System.Linq.Expressions.dll
+ True
+ True
+
+
+ ..\packages\System.Net.Http.4.3.0\lib\net46\System.Net.Http.dll
+ True
+ True
+
+
+ ..\packages\System.Net.Sockets.4.3.0\lib\net46\System.Net.Sockets.dll
+ True
+ True
+
+
+
+ ..\packages\System.Reflection.4.3.0\lib\net462\System.Reflection.dll
+ True
+ True
+
+
+ ..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll
+ True
+ True
+
+
+ ..\packages\System.Runtime.Extensions.4.3.0\lib\net462\System.Runtime.Extensions.dll
+ True
+ True
+
+
+ ..\packages\System.Runtime.InteropServices.4.3.0\lib\net463\System.Runtime.InteropServices.dll
+ True
+ True
+
+
+ ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll
+ True
+ True
+
+
+ ..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net463\System.Security.Cryptography.Algorithms.dll
+ True
+ True
+
+
+ ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll
+ True
+ True
+
+
+ ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll
+ True
+ True
+
+
+ ..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll
+ True
+ True
+
+
+ ..\packages\System.Text.RegularExpressions.4.3.0\lib\net463\System.Text.RegularExpressions.dll
+ True
+ True
+
-
4.0
+
+ ..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll
+ True
+ True
+
@@ -97,9 +237,13 @@
True
True
+
+
+
+
@@ -183,4 +327,11 @@
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
\ No newline at end of file
diff --git a/BodyshopUploader/Properties/Resources.Designer.cs b/BodyshopUploader/Properties/Resources.Designer.cs
index 38d2755..58301f0 100644
--- a/BodyshopUploader/Properties/Resources.Designer.cs
+++ b/BodyshopUploader/Properties/Resources.Designer.cs
@@ -60,6 +60,42 @@ namespace BodyshopUploader.Properties {
}
}
+ ///
+ /// Looks up a localized string similar to An issue has occured. Please check the log files..
+ ///
+ public static string Error_Generic {
+ get {
+ return ResourceManager.GetString("Error_Generic", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The username and password combination is not valid. Please try again. .
+ ///
+ public static string Error_Login {
+ get {
+ return ResourceManager.GetString("Error_Login", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Too many login attempts..
+ ///
+ public static string Error_Login_Attempts {
+ get {
+ return ResourceManager.GetString("Error_Login_Attempts", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to An unknown error occured while logging in. Please check the log files..
+ ///
+ public static string Error_Login_Unknown {
+ get {
+ return ResourceManager.GetString("Error_Login_Unknown", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Exit.
///
diff --git a/BodyshopUploader/Properties/Resources.resx b/BodyshopUploader/Properties/Resources.resx
index f5eed73..79bbf2d 100644
--- a/BodyshopUploader/Properties/Resources.resx
+++ b/BodyshopUploader/Properties/Resources.resx
@@ -117,6 +117,18 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ An issue has occured. Please check the log files.
+
+
+ The username and password combination is not valid. Please try again.
+
+
+ Too many login attempts.
+
+
+ An unknown error occured while logging in. Please check the log files.
+
Exit
diff --git a/BodyshopUploader/Properties/Settings.Designer.cs b/BodyshopUploader/Properties/Settings.Designer.cs
index c02164e..7f43b15 100644
--- a/BodyshopUploader/Properties/Settings.Designer.cs
+++ b/BodyshopUploader/Properties/Settings.Designer.cs
@@ -8,23 +8,42 @@
//
//------------------------------------------------------------------------------
-namespace BodyshopUploader.Properties
-{
-
-
+namespace BodyshopUploader.Properties {
+
+
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
- internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
- {
-
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.4.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
-
- public static Settings Default
- {
- get
- {
+
+ public static Settings Default {
+ get {
return defaultInstance;
}
}
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("")]
+ public string Username {
+ get {
+ return ((string)(this["Username"]));
+ }
+ set {
+ this["Username"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public global::System.Security.SecureString Password {
+ get {
+ return ((global::System.Security.SecureString)(this["Password"]));
+ }
+ set {
+ this["Password"] = value;
+ }
+ }
}
}
diff --git a/BodyshopUploader/Properties/Settings.settings b/BodyshopUploader/Properties/Settings.settings
index 033d7a5..e75ac4e 100644
--- a/BodyshopUploader/Properties/Settings.settings
+++ b/BodyshopUploader/Properties/Settings.settings
@@ -1,7 +1,12 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/BodyshopUploader/Utils/AppMetaData.cs b/BodyshopUploader/Utils/AppMetaData.cs
new file mode 100644
index 0000000..0df018d
--- /dev/null
+++ b/BodyshopUploader/Utils/AppMetaData.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BodyshopUploader.Utils
+{
+ public static class AppMetaData
+ {
+ public static string FirebaseAPIKey_DEV = "AIzaSyDV9MsSHZmpLtjoaTK_ObvjFaJ-nMSd2KA";
+
+ }
+}
diff --git a/BodyshopUploader/Utils/Auth.cs b/BodyshopUploader/Utils/Auth.cs
new file mode 100644
index 0000000..22a132c
--- /dev/null
+++ b/BodyshopUploader/Utils/Auth.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Firebase.Auth;
+using System.Timers;
+
+namespace BodyshopUploader.Utils
+{
+ public static class Auth
+ {
+ private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
+ public static FirebaseAuthLink authlink;
+ public static string authToken;
+ static string refreshToken;
+ static int tokenExpiration;
+ static FirebaseAuthProvider ap = new FirebaseAuthProvider(new FirebaseConfig(Utils.AppMetaData.FirebaseAPIKey_DEV)); //TODO: Update this to be a dynamic key. Perhaps a function that fetches?
+ private static Timer tokenTimer = new Timer();
+
+ public async static Task<(bool, string)> LoginAsync(string Username, string Password)
+ {
+ try
+ {
+ authlink = await ap.SignInWithEmailAndPasswordAsync(Username, Password);
+ authToken = authlink.FirebaseToken;
+ refreshToken = authlink.RefreshToken;
+ tokenExpiration = authlink.ExpiresIn;
+ logger.Trace("Firebase Auth Token {0}.", authToken);
+ logger.Trace("Firebase Refresh Token {0}.", refreshToken);
+ logger.Trace("Firebase Auth Token expires in {0} seconds.", tokenExpiration);
+
+ tokenTimer.Interval = (tokenExpiration - 600) * 1000; //Set the token to refresh 10 minutes before it has to.
+ tokenTimer.Elapsed += TokenTimer_Elapsed;
+ return (true, null);
+ }
+ catch (FirebaseAuthException Ex)
+ {
+ switch (Ex.Reason)
+ {
+ case AuthErrorReason.WrongPassword:
+ logger.Error("Incorrect password provided for user.");
+ return (false, Properties.Resources.Error_Login);
+
+ case AuthErrorReason.UnknownEmailAddress:
+ logger.Error("User does not exist.");
+ return (false, Properties.Resources.Error_Login);
+ case AuthErrorReason.TooManyAttemptsTryLater:
+ logger.Error("Too many attempts logging in.");
+ return (false, Properties.Resources.Error_Login_Attempts);
+ default:
+ logger.Error(Ex, "Unknown error occured while logging in. {0}", Ex.Reason);
+ return (false, Properties.Resources.Error_Login_Unknown);
+ }
+ }
+ catch (Exception Ex)
+ {
+ logger.Error(Ex, "Unknown error encountered while obtaining auth token.");
+ return (false, Properties.Resources.Error_Generic);
+ }
+ }
+
+ private static void TokenTimer_Elapsed(object sender, ElapsedEventArgs e)
+ {
+ //Gotta do some stuff now that i got a new token!
+ //Maybe the token auto refreshes?
+ }
+ }
+}
diff --git a/BodyshopUploader/Utils/LoginHelpers.cs b/BodyshopUploader/Utils/LoginHelpers.cs
new file mode 100644
index 0000000..4489986
--- /dev/null
+++ b/BodyshopUploader/Utils/LoginHelpers.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BodyshopUploader.Utils
+{
+ public static class LoginHelpers
+ {
+ public static void SaveLoginSettings(string Username, SecureString Password)
+ {
+ Properties.Settings.Default.Username = Username;
+ //Todo: Figure out how to save the secure string. Perhaps serialize to JSON?
+ Properties.Settings.Default.Password = Password;
+ Properties.Settings.Default.Save();
+ }
+
+ public static string DecodePassword (SecureString s)
+ {
+ //Manage the secure string for the password.
+ IntPtr stringPointer = Marshal.SecureStringToBSTR(s);
+ string UP = Marshal.PtrToStringBSTR(stringPointer);
+ Marshal.ZeroFreeBSTR(stringPointer);
+ return UP;
+ }
+ }
+}
diff --git a/BodyshopUploader/Utils/UiConverters.cs b/BodyshopUploader/Utils/UiConverters.cs
new file mode 100644
index 0000000..b49dc57
--- /dev/null
+++ b/BodyshopUploader/Utils/UiConverters.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Data;
+
+namespace BodyshopUploader.Utils
+{
+ public class BoolVisibilityConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ if ((bool)value)
+ return Visibility.Visible;
+ else
+ return Visibility.Collapsed;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotSupportedException("Two-way binding not supported by BoolVisibilityConverter");
+ }
+ }
+
+ public class NullVisibilityConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ if (value == null)
+ return Visibility.Collapsed;
+ else
+ return Visibility.Visible;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotSupportedException("Two-way binding not supported by ZeroVisibilityConverter");
+ }
+ }
+
+}
diff --git a/BodyshopUploader/ViewModels/LoginViewModel.commands.cs b/BodyshopUploader/ViewModels/LoginViewModel.commands.cs
index 8f4e67f..ec0f6b0 100644
--- a/BodyshopUploader/ViewModels/LoginViewModel.commands.cs
+++ b/BodyshopUploader/ViewModels/LoginViewModel.commands.cs
@@ -1,24 +1,24 @@
using System;
+using System.Windows;
using System.Windows.Input;
namespace BodyshopUploader.ViewModels
{
public partial class LoginViewModel : BaseViewModel
{
- private ICommand _openMainCommand;
- public ICommand OpenMainCommand
+ private ICommand _loginCommand;
+ public ICommand LoginCommand
{
get
{
- if (_openMainCommand == null)
+ if (_loginCommand == null)
{
- _openMainCommand = new RelayCommand(
- p => true,
- p => { Views.Main m = new Views.Main(); m.Show(); });
+ _loginCommand = new RelayCommand(
+ p => !string.IsNullOrEmpty(UserName) && UserPassword?.Length > 6,
+ async p => { await LoginAsync(p as Window); });
}
- return _openMainCommand;
+ return _loginCommand;
}
}
-
}
}
diff --git a/BodyshopUploader/ViewModels/LoginViewModel.cs b/BodyshopUploader/ViewModels/LoginViewModel.cs
index 889a083..7bfc1a1 100644
--- a/BodyshopUploader/ViewModels/LoginViewModel.cs
+++ b/BodyshopUploader/ViewModels/LoginViewModel.cs
@@ -1,18 +1,37 @@
-using System;
+
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using System.Windows;
namespace BodyshopUploader.ViewModels
-{
+{
public partial class LoginViewModel : BaseViewModel
- {
+ {
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
public LoginViewModel()
{
- logger.Trace("We're in boys.");
+ logger.Trace("Login VM Created.");
+ }
+
+ private async Task LoginAsync(Window W)
+ {
+ Loading = true;
+
+ Utils.LoginHelpers.SaveLoginSettings(UserName, UserPassword);
+
+ logger.Trace("Attempting to login as user: {0}", UserName);
+ (Error, ErrorMsg) = await Utils.Auth.LoginAsync(UserName, Utils.LoginHelpers.DecodePassword(UserPassword));
+ if(ErrorMsg ==null)
+ {
+ Views.Main m = new Views.Main();
+ m.Show();
+ W.Hide();
+ }
+ Loading = false;
}
}
}
diff --git a/BodyshopUploader/ViewModels/LoginViewModel.props.cs b/BodyshopUploader/ViewModels/LoginViewModel.props.cs
index be93b78..27301e5 100644
--- a/BodyshopUploader/ViewModels/LoginViewModel.props.cs
+++ b/BodyshopUploader/ViewModels/LoginViewModel.props.cs
@@ -2,25 +2,47 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
+using System.Security;
using System.Text;
using System.Threading.Tasks;
namespace BodyshopUploader.ViewModels
{
- public partial class LoginViewModel: BaseViewModel
+ public partial class LoginViewModel : BaseViewModel
{
- private ObservableCollection _invoiceList;
- public ObservableCollection InvoiceList
+ private string _userName = Properties.Settings.Default.Username;
+ public string UserName
{
- get { return _invoiceList; }
- set { SetProperty(ref _invoiceList, value); }
+ get { return _userName; }
+ set { SetProperty(ref _userName, value); }
}
- private int _progress = 5;
- public int Progress
+ private SecureString _userPassword = Properties.Settings.Default.Password;
+ public SecureString UserPassword
{
- get { return _progress; }
- set { SetProperty(ref _progress, value); }
+ get { return _userPassword; }
+ set { SetProperty(ref _userPassword, value); }
+ }
+
+ private bool _error = false;
+ public bool Error
+ {
+ get { return _error; }
+ set { SetProperty(ref _error, value); }
+ }
+
+ private string _errorMsg;
+ public string ErrorMsg
+ {
+ get { return _errorMsg; }
+ set { SetProperty(ref _errorMsg, value); }
+ }
+
+ private bool _loading = false;
+ public bool Loading
+ {
+ get { return _loading; }
+ set { SetProperty(ref _loading, value); }
}
}
}
diff --git a/BodyshopUploader/Views/Login.xaml b/BodyshopUploader/Views/Login.xaml
index 53187f4..f90f512 100644
--- a/BodyshopUploader/Views/Login.xaml
+++ b/BodyshopUploader/Views/Login.xaml
@@ -9,15 +9,56 @@
Title="{x:Static p:Resources.Title_Login}"
Height="450"
Width="800"
- xmlns:p="clr-namespace:BodyshopUploader.Properties">
+ xmlns:p="clr-namespace:BodyshopUploader.Properties"
+ xmlns:util="clr-namespace:BodyshopUploader.Utils"
+ xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
+ TextElement.Foreground="{DynamicResource MaterialDesignBody}"
+ TextElement.FontWeight="Regular"
+ TextElement.FontSize="13"
+ TextOptions.TextFormattingMode="Ideal"
+ TextOptions.TextRenderingMode="Auto"
+ Background="{DynamicResource MaterialDesignPaper}"
+ FontFamily="{DynamicResource MaterialDesignFont}"
+ Closing="Window_Closing">
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/BodyshopUploader/Views/Login.xaml.cs b/BodyshopUploader/Views/Login.xaml.cs
index bb4aa09..438bfe3 100644
--- a/BodyshopUploader/Views/Login.xaml.cs
+++ b/BodyshopUploader/Views/Login.xaml.cs
@@ -5,6 +5,7 @@ using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
+using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
@@ -23,5 +24,43 @@ namespace BodyshopUploader.Views
{
InitializeComponent();
}
+ private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
+ {
+ if (this.DataContext != null)
+ { ((dynamic)this.DataContext).UserPassword = ((PasswordBox)sender).SecurePassword; }
+ }
+
+ private void PasswordBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
+ {
+ var pb = sender as PasswordBox;
+
+ if ((Keyboard.GetKeyStates(Key.CapsLock) & KeyStates.Toggled) == KeyStates.Toggled)
+ {
+ if (pb.ToolTip == null)
+ {
+ ToolTip tt = new ToolTip();
+ tt.Content = "Warning: CapsLock is on";
+ tt.PlacementTarget = sender as UIElement;
+ tt.Placement = PlacementMode.Right;
+ pb.ToolTip = tt;
+ tt.IsOpen = true;
+ }
+ }
+ else
+ {
+ var currentToolTip = pb.ToolTip as ToolTip;
+ if (currentToolTip != null)
+ {
+ currentToolTip.IsOpen = false;
+ }
+
+ pb.ToolTip = null;
+ }
+ }
+
+ private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
+ {
+ Application.Current.Shutdown(0);
+ }
}
}
diff --git a/BodyshopUploader/packages.config b/BodyshopUploader/packages.config
index 8168088..4c5ee6e 100644
--- a/BodyshopUploader/packages.config
+++ b/BodyshopUploader/packages.config
@@ -1,8 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file