Compare commits

...

30 Commits

Author SHA1 Message Date
852ec739cb Implement New Room Entry Control
Version Bump
2025-11-21 16:17:48 -08:00
98f62e976c Rework Contacts Tab Style
Fixed Messages Getting Cutoff Slightly At The End
Version Bump
2025-11-18 22:06:28 -08:00
bfcc445c63 Version Bump 2025-11-18 16:13:55 -08:00
987fae22f0 Implement New Message Control In DM's 2025-11-18 16:13:00 -08:00
95daf24473 Version Bump 2025-11-17 16:55:27 -08:00
256e10a7ba Fix Index Out Of Range Exception In AddMessage (im stupid im dumb im stupid im du-) 2025-11-17 16:55:11 -08:00
5016e63a38 Rework Chat Room Form (again)
Version Bump
2025-11-17 16:40:15 -08:00
0d71fe5983 Version Bump 2025-11-15 12:33:13 -08:00
55323321d0 Merge pull request 'Rework Lobby And Use ListViews For Messages' (#6) from lobby-rework into master
Reviewed-on: Moonbase/qtc-net-client#6
2025-11-15 12:30:43 -08:00
ca895d1b97 ChatRoom Form Now Joins Room Instead Of Main Form
Chat Message List Design Changes
2025-11-15 12:29:32 -08:00
89d3c60bde Rework Lobby
Use ListViews For Messages
2025-11-14 18:37:43 -08:00
391b182f4c Remove Explicit Transparency On Profile Images
Fix Store Tab Being Multi Selectable
2025-11-14 17:09:16 -08:00
f1648a12c2 Sign Out Should Delete Stored Credential 2025-11-12 13:58:30 -08:00
4361a69506 Version Bump 2025-11-12 13:44:49 -08:00
b358bb54d0 Implement Better Image Creating
Change Remember Me Checkbox Text To 30 Days
Bug Fixes (i can't remember what i was doing here)
2025-11-12 13:44:22 -08:00
a95d012d69 Update Packages That Could Be Updated
Rework Missed Refresh Token Code
Minor Version Bump
2025-09-21 14:16:41 -07:00
d1d3af2ec9 Rework Refresh Token Storage Solution To Use Windows Credentials API
Minor Version Bump
2025-09-21 13:49:11 -07:00
4e61a1d7b9 Version Bump 2025-08-03 15:00:37 -07:00
446745d4df Implement CreateProfileImage To Combine Precense Icon, Profile Image, and Cosmetic To Make Final Profile Image 2025-08-03 15:00:09 -07:00
00df7505a7 Move Cosmetic Download To Main Form Thread 2025-08-03 14:27:00 -07:00
b17d391406 Minor Version Bump 2025-07-31 15:21:50 -07:00
2092d2c6d3 Keep Default KA Values 2025-07-31 15:05:03 -07:00
fd743dcb42 Do Not Set Server Timeout (it was the default value anyways) 2025-07-31 15:00:37 -07:00
9214460927 Server Timeout = 30s
Keep-Alive Interval  = 1m
2025-07-31 14:59:13 -07:00
1b30636937 Configure TimeSpans For ServerTimeout And KeepAliveInterval 2025-07-31 10:18:57 -07:00
72d9b99c4c Refresh Session Everytime Gateway Connection Is Used To Prevent The Server From Aborting Requests 2025-07-31 10:06:12 -07:00
c7137e4c7e Version Bump 2025-07-27 13:56:55 -07:00
4ee524778d Merge pull request 'Email Features' (#5) from email-features into master
Reviewed-on: Moonbase/qtc-net-client#5
2025-07-27 13:55:57 -07:00
cfcc5ad4c1 Message Box On Register To Inform User Of Email Verification 2025-07-27 13:54:17 -07:00
b81b059177 Initial Implementation Of Email Features 2025-07-27 13:51:44 -07:00
36 changed files with 2364 additions and 781 deletions

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace QtCNETAPI.Dtos.User
{
public class UserPasswordResetDto
{
public string Token { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
}
}

View File

@ -6,5 +6,6 @@
public string Name { get; set; } = string.Empty;
public string CreatorId { get; set; } = string.Empty;
public DateTime CreatedAt { get; set; } = new DateTime();
public int UserCount { get; set; } = 0;
}
}

View File

@ -9,6 +9,7 @@
public string Role { get; set; } = string.Empty;
public string PasswordHash { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public bool IsEmailVerified { get; set; } = false;
public DateTime DateOfBirth { get; set; }
public DateTime CreatedAt { get; set; }
public int Status { get; set; } = 0;
@ -16,6 +17,7 @@
public int StockAmount { get; set; } = 0;
public DateTime LastCurrencySpin { get; set; }
public int ActiveProfileCosmetic { get; set; } = 0;
public string CurrentRoomId { get; set; } = string.Empty;
public virtual IEnumerable<RefreshToken>? RefreshTokens { get; }
public virtual IEnumerable<Contact>? ContactsMade { get; }

View File

@ -7,10 +7,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Meziantou.Framework.Win32.CredentialManager" Version="1.7.6" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.16" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.5" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.9" />
<PackageReference Include="RestSharp" Version="112.1.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.10.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.14.0" />
</ItemGroup>
</Project>

View File

@ -15,6 +15,8 @@ namespace QtCNETAPI.Services.ApiService
private RestClient _client;
private LoggingService _loggingService;
private CredentialService _credService = new();
internal string? sessionToken;
internal string apiUri;
@ -235,9 +237,9 @@ namespace QtCNETAPI.Services.ApiService
}
}
public async Task<ServiceResponse<User>> LoginAsync(UserLoginDto userLoginDto)
public async Task<ServiceResponse<string>> LoginAsync(UserLoginDto userLoginDto)
{
var serviceResponse = new ServiceResponse<User>();
var serviceResponse = new ServiceResponse<string>();
try
{
@ -257,13 +259,11 @@ namespace QtCNETAPI.Services.ApiService
{
SessionToken = response.Data!;
await File.WriteAllTextAsync("./session.token", response.Message);
var user = await SetCurrentUser();
serviceResponse.Success = true;
if (response.Message != null) serviceResponse.Message = response.Message;
serviceResponse.Data = user;
serviceResponse.Data = response.Message;
}
else
{
@ -280,6 +280,72 @@ namespace QtCNETAPI.Services.ApiService
return serviceResponse;
}
public async Task<ServiceResponse<bool>> ResendVerificationEmail(string email)
{
var serviceResponse = new ServiceResponse<bool>();
var restRequest = new RestRequest($"auth/resend-verification-email")
.AddQueryParameter("email", email);
var response = await _client.PostAsync<ServiceResponse<bool>>(restRequest);
if (response != null)
{
serviceResponse.Success = true;
serviceResponse.Data = response.Data;
}
else
{
serviceResponse.Success = false;
serviceResponse.Message = "API never responded.";
}
return serviceResponse;
}
public async Task<ServiceResponse<bool>> SendPasswordResetEmail(string email)
{
var serviceResponse = new ServiceResponse<bool>();
var restRequest = new RestRequest($"auth/request-password-reset")
.AddQueryParameter("email", email);
var response = await _client.PostAsync<ServiceResponse<bool>>(restRequest);
if (response != null)
{
serviceResponse.Success = true;
serviceResponse.Data = response.Data;
}
else
{
serviceResponse.Success = false;
serviceResponse.Message = "API never responded.";
}
return serviceResponse;
}
public async Task<ServiceResponse<bool>> ResetPassword(UserPasswordResetDto request)
{
var serviceResponse = new ServiceResponse<bool>();
var restRequest = new RestRequest($"auth/reset-password")
.AddJsonBody(request);
var response = await _client.PostAsync<ServiceResponse<bool>>(restRequest);
if (response != null)
{
serviceResponse.Success = true;
serviceResponse.Data = response.Data;
}
else
{
serviceResponse.Success = false;
serviceResponse.Message = "API never responded.";
}
return serviceResponse;
}
public async Task<User> SetCurrentUser()
{
var userRequest = new RestRequest("users/user-authorized")
@ -347,21 +413,23 @@ namespace QtCNETAPI.Services.ApiService
public async Task<ServiceResponse<string>> RefreshSessionIfInvalid()
{
var tokenHandler = new JwtSecurityTokenHandler();
var refToken = await File.ReadAllTextAsync("./session.token");
var refToken = _credService.GetAccessToken(); // fuck CA1416, if this is being ran on linux it should just crash (theoretically)
if (refToken == null)
{
// treat as session expired
return new ServiceResponse<string> { Success = false, Message = "Refresh Token Not Found. Session Expired." };
}
JwtSecurityToken token = tokenHandler.ReadJwtToken(SessionToken);
if(DateTime.Compare(DateTime.UtcNow, token.ValidTo) > 0)
{
if (!File.Exists("./session.token")) { return new ServiceResponse<string> { Success = false, Message = "Session File Not Found. Session Expired." }; }
var result = await RefreshLogin(refToken);
if (result == null || result.Success == false)
{
File.Delete("./session.token");
return new ServiceResponse<string> { Success = false, Message = "Session Expired." };
return new ServiceResponse<string> { Success = false, Message = "Session Expired." }; // logging in again should overwrite old token
} else return new ServiceResponse<string> { Success = true, Data = refToken };
} else return new ServiceResponse<string> { Success = true, Data = refToken };
}

View File

@ -23,7 +23,10 @@ namespace QtCNETAPI.Services.ApiService
public Task<ServiceResponse<List<UserInformationDto>>> GetOnlineUsersAsync();
public Task<ServiceResponse<List<UserInformationDto>>> GetAllUsersAsync();
public Task<ServiceResponse<User>> DeleteUserById(string id);
public Task<ServiceResponse<User>> LoginAsync(UserLoginDto userLoginDto);
public Task<ServiceResponse<string>> LoginAsync(UserLoginDto userLoginDto);
public Task<ServiceResponse<bool>> ResendVerificationEmail(string email);
public Task<ServiceResponse<bool>> SendPasswordResetEmail(string email);
public Task<ServiceResponse<bool>> ResetPassword(UserPasswordResetDto request);
public Task<ServiceResponse<User>> RefreshLogin(string refreshToken);
public Task<ServiceResponse<string>> RefreshSessionIfInvalid();
public Task<User> SetCurrentUser();

View File

@ -0,0 +1,42 @@
using Meziantou.Framework.Win32;
namespace QtCNETAPI.Services
{
public class CredentialService()
{
/*
* NOTE *
This does not work on other platforms such as Linux or macOS.
I will probably recode the legacy way of doing this for those other platforms.
*/
public void SaveAccessToken(string username, string accessToken)
{
string applicationName = "QtC.NET";
if (System.Diagnostics.Debugger.IsAttached) applicationName = "QtC.NET.Development";
CredentialManager.WriteCredential(applicationName, username, accessToken, $"Access Token For User {username} On QtC.NET", CredentialPersistence.LocalMachine);
}
public void DeleteAccessToken()
{
string applicationName = "QtC.NET";
if (System.Diagnostics.Debugger.IsAttached) applicationName = "QtC.NET.Development";
CredentialManager.DeleteCredential(applicationName);
}
public string? GetAccessToken()
{
string applicationName = "QtC.NET";
if (System.Diagnostics.Debugger.IsAttached) applicationName = "QtC.NET.Development";
var credential = CredentialManager.ReadCredential(applicationName);
if (credential == null) return null;
return credential.Password;
}
}
}

View File

@ -12,7 +12,6 @@ namespace QtCNETAPI.Services.GatewayService
internal string gwBaseUri = GWUrl;
public Room? CurrentRoom { get; private set; }
public bool InLobby { get; private set; }
public HubConnection? HubConnection { get; private set; }
@ -36,9 +35,6 @@ namespace QtCNETAPI.Services.GatewayService
public async Task StartAsync()
{
// just to be safe (it doesn't load the server since it shouldn't request a new one unless its actually expired)
await _apiService.RefreshSessionIfInvalid();
// build connection
var gwConBuilder = new HubConnectionBuilder()
.WithAutomaticReconnect()
@ -51,8 +47,14 @@ namespace QtCNETAPI.Services.GatewayService
})
.WithUrl(gwBaseUri, options =>
{
options.AccessTokenProvider = () => Task.FromResult(_apiService.SessionToken);
});
options.AccessTokenProvider = async () =>
{
// this should hopefully refresh the session every time the gateway connection is used to prevent connection aborts
await _apiService.RefreshSessionIfInvalid();
return _apiService.SessionToken;
};
})
.WithStatefulReconnect();
HubConnection = gwConBuilder.Build();
// register events
@ -117,62 +119,35 @@ namespace QtCNETAPI.Services.GatewayService
}
}
public async Task JoinLobbyAsync()
public async Task JoinRoomAsync(Room? room = null)
{
await _apiService.RefreshSessionIfInvalid();
if (HubConnection == null || HubConnection.State != HubConnectionState.Connected) throw new InvalidOperationException("Function was called before connection was made.");
await HubConnection.SendAsync("JoinLobby", _apiService.CurrentUser);
InLobby = true;
CurrentRoom = null;
}
public async Task JoinRoomAsync(Room room)
{
await _apiService.RefreshSessionIfInvalid();
if (HubConnection == null || HubConnection.State != HubConnectionState.Connected) throw new InvalidOperationException("Function was called before connection was made.");
if (InLobby == true)
// assume user is trying to join lobby if room is null (does not have db entry)
room ??= new Room
{
await HubConnection.SendAsync("LeaveLobby", _apiService.CurrentUser);
InLobby = false;
}
else if (CurrentRoom != null)
{
await HubConnection.SendAsync("LeaveRoom", _apiService.CurrentUser, CurrentRoom);
}
Id = "LOBBY",
Name = "Lobby"
};
if (CurrentRoom != null) await HubConnection.SendAsync("LeaveRoom", _apiService.CurrentUser, CurrentRoom);
await HubConnection.SendAsync("JoinRoom", _apiService.CurrentUser, room);
CurrentRoom = room;
}
public async Task LeaveRoomAsync()
{
await _apiService.RefreshSessionIfInvalid();
if (HubConnection == null || HubConnection.State != HubConnectionState.Connected) throw new InvalidOperationException("Function was called before connection was made.");
if (InLobby)
{
await HubConnection.SendAsync("LeaveLobby", _apiService.CurrentUser);
InLobby = false;
}
else
{
await HubConnection.SendAsync("LeaveRoom", _apiService.CurrentUser, CurrentRoom);
CurrentRoom = null;
}
if (CurrentRoom != null) await HubConnection.SendAsync("LeaveRoom", _apiService.CurrentUser, CurrentRoom);
CurrentRoom = null;
}
public async Task PostMessageAsync(Message message)
{
await _apiService.RefreshSessionIfInvalid();
if (HubConnection == null || HubConnection.State != HubConnectionState.Connected) throw new InvalidOperationException("Function was called before connection was made.");
await HubConnection.SendAsync("SendMessage", _apiService.CurrentUser, message, InLobby, CurrentRoom);
await HubConnection.SendAsync("SendMessage", _apiService.CurrentUser, message, CurrentRoom);
}
public async Task SendDirectMessageAsync(UserInformationDto user, Message message)
@ -186,8 +161,6 @@ namespace QtCNETAPI.Services.GatewayService
public async Task UpdateStatus(int status)
{
await _apiService.RefreshSessionIfInvalid();
if (HubConnection == null || HubConnection.State != HubConnectionState.Connected) throw new InvalidOperationException("Function was called before connection was made.");
await HubConnection.SendAsync("UpdateStatus", _apiService.CurrentUser, status);

View File

@ -18,10 +18,7 @@ namespace QtCNETAPI.Services.GatewayService
/// The Current Room The Current User Is In
/// </summary>
public Room? CurrentRoom { get; }
/// <summary>
/// Is The User Currently In The Lobby?
/// </summary>
public bool InLobby { get; }
/// <summary>
/// The Current Connection To The Gateway
/// </summary>
@ -47,20 +44,13 @@ namespace QtCNETAPI.Services.GatewayService
/// <returns></returns>
public Task DisposeAsync();
/// <summary>
/// Joins The Lobby Of The Server
/// </summary>
/// <returns></returns>
/// <exception cref="InvalidOperationException">Thrown if the function is called before the connection is established.</exception>
public Task JoinLobbyAsync();
/// <summary>
/// Joins The Current User To A Room On The Server
/// </summary>
/// <param name="room">Room To Join</param>
/// <returns></returns>
/// <exception cref="InvalidOperationException">Thrown if the function is called before the connection is established.</exception>
public Task JoinRoomAsync(Room room);
public Task JoinRoomAsync(Room? room = null);
/// <summary>
/// Leaves The Current Room The Current User Is In

View File

@ -0,0 +1,148 @@
using qtc_net_client_2.Properties;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace qtc_net_client_2.Controls
{
public class ChatMessageControl : Control
{
public Image? Avatar { get; set; }
public string Username = "Username";
public string Message = "Message";
private Font usernameFont = new("Segoe UI", 9, FontStyle.Bold);
private Font messageFont = new("Segoe UI", 9, FontStyle.Regular);
private Font messageFontBold = new("Segoe UI", 10, FontStyle.Bold);
public ChatMessageControl()
{
DoubleBuffered = true;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
int avatarSize = 32;
int padding = 6;
// first, draw the avatar
Rectangle pfpRect = new(padding, padding, avatarSize, avatarSize);
e.Graphics.DrawImage(Avatar ?? Resources.DefaultPfp, pfpRect);
// then draw the username
int textLeft = padding * 2 + avatarSize;
int textWidth = Width - textLeft - padding;
Rectangle usernameRect = new(textLeft, padding, textWidth, 20);
e.Graphics.DrawString(Username, usernameFont, Brushes.Black, usernameRect);
// finally draw the message
int messageTop = usernameRect.Bottom + 2;
Rectangle messageRect = new(textLeft, messageTop, textWidth, Height - messageTop - padding);
StringFormat fmt = new()
{
Trimming = StringTrimming.Word,
FormatFlags = 0,
Alignment = StringAlignment.Near
};
if (Username.Contains("Server"))
{
e.Graphics.DrawString(Message, messageFontBold, Brushes.Black, messageRect, fmt);
return;
}
e.Graphics.DrawString(Message, messageFont, Brushes.Black, messageRect, fmt);
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
Height = CalculateHeight(Width);
}
public int CalculateHeight(int width)
{
int padding = 6;
int avatarSize = 32;
int textLeft = padding * 2 + avatarSize;
int textWidth = width - textLeft - padding;
using (Graphics g = CreateGraphics())
{
SizeF usernameSize = g.MeasureString(Username, usernameFont, textWidth);
SizeF messageSize = g.MeasureString(Message, messageFont, textWidth);
int totalHeight = padding + (int)usernameSize.Height + 2 + (int)messageSize.Height + padding + 5;
return Math.Max(totalHeight, avatarSize + 2 * padding);
}
}
}
public class ChatMessageControlMinimal : Control
{
public string Username = "Username";
public string Message = "Message";
private Font usernameFont = new("Segoe UI", 9, FontStyle.Bold);
private Font messageFont = new("Segoe UI", 9, FontStyle.Regular);
public ChatMessageControlMinimal()
{
DoubleBuffered = true;
MinimumSize = new Size(150, 20);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
int padding = 6;
// first draw the username
int textWidth = Width - padding * 2;
Rectangle usernameRect = new(padding, padding, textWidth, 20);
e.Graphics.DrawString(Username, usernameFont, Brushes.Black, usernameRect);
// finally draw the message
int messageTop = usernameRect.Bottom + 2;
Rectangle messageRect = new(padding, messageTop, textWidth, Height - messageTop - padding);
StringFormat fmt = new()
{
Trimming = StringTrimming.Word,
FormatFlags = 0,
Alignment = StringAlignment.Near
};
e.Graphics.DrawString(Message, messageFont, Brushes.Black, messageRect, fmt);
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
Height = CalculateHeight(Width);
}
public int CalculateHeight(int width)
{
int padding = 6;
int textWidth = width - padding * 2;
using (Graphics g = CreateGraphics())
{
SizeF usernameSize = g.MeasureString(Username, usernameFont, textWidth);
SizeF messageSize = g.MeasureString(Message, messageFont, textWidth);
int totalHeight = padding + (int)usernameSize.Height + 2 + (int)messageSize.Height + padding + 5;
return totalHeight;
}
}
}
}

View File

@ -0,0 +1,92 @@
using Accessibility;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using qtc_net_client_2.Properties;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace qtc_net_client_2.Controls
{
public class ContactEntryControl : Control
{
public Image? Avatar { get; set; }
public string Username = "Username";
public Color StatusColor = Color.Gray;
private Font? usernameFont;
public event EventHandler? ContactDoubleClicked;
private bool IsHoveredOn;
public ContactEntryControl()
{
// reduce flicker
SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.ResizeRedraw |
ControlStyles.UserPaint |
ControlStyles.OptimizedDoubleBuffer, true);
Height = 36;
}
protected override void OnPaintBackground(PaintEventArgs pevent) { } // prevent this
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
Rectangle rect = ClientRectangle;
using var brush = new LinearGradientBrush(rect, StatusColor, BackColor, LinearGradientMode.Horizontal);
Color usernameForeColor = Color.Black;
if(IsHoveredOn)
{
usernameForeColor = Color.White;
usernameFont = new Font("Segoe UI", 9, FontStyle.Bold | FontStyle.Underline);
}
else
{
usernameFont = new Font("Segoe UI", 9, FontStyle.Bold);
}
e.Graphics.FillRectangle(brush, rect);
int margin = 6;
int imgSize = 32;
Rectangle avatarRect = new(margin, (Height - imgSize) / 2, imgSize, imgSize);
e.Graphics.DrawImage(Avatar ?? Resources.DefaultPfp, avatarRect);
int textLeft = avatarRect.Right + margin;
Rectangle rectText = new(textLeft, 0, Width - textLeft - 8, Height - 16);
TextRenderer.DrawText(e.Graphics, Username, usernameFont, rectText, usernameForeColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter);
}
protected override void OnMouseDoubleClick(MouseEventArgs e)
{
base.OnMouseDoubleClick(e);
ContactDoubleClicked?.Invoke(this, EventArgs.Empty);
}
protected override void OnMouseHover(EventArgs e)
{
base.OnMouseHover(e);
IsHoveredOn = true;
Invalidate();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
IsHoveredOn = false;
Invalidate();
}
}
}

View File

@ -0,0 +1,95 @@
using qtc_net_client_2.Properties;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;
namespace qtc_net_client_2.Controls
{
public class RoomEntryControl : Control
{
public Image Image = Resources.RoomsChatIcon;
public string RoomName = "Room";
public bool HideUserCount = false;
public int RoomUserCount = 0;
private Font? nameFont;
private Color nameColor;
private Font userCountFont = new("Segoe UI", 9, FontStyle.Bold);
private Color userCountColor = Color.Gray;
private bool IsHoveredOn = false;
public event EventHandler? OnRoomDoubleClicked;
public RoomEntryControl()
{
// reduce flicker
SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.ResizeRedraw |
ControlStyles.UserPaint |
ControlStyles.OptimizedDoubleBuffer, true);
Height = 36;
}
protected override void OnPaint(PaintEventArgs e)
{
if(IsHoveredOn)
{
nameFont = new("Segoe UI", 9, FontStyle.Bold | FontStyle.Underline);
nameColor = Color.LightGray;
} else
{
nameFont = new("Segoe UI", 9, FontStyle.Bold);
nameColor = Color.Black;
}
int margin = 6;
int imageSize = 32;
Rectangle imageRect = new(margin, (Height - imageSize) / 2, imageSize, imageSize);
e.Graphics.DrawImage(Image, imageRect);
int nameLeft = imageRect.Right + margin;
Rectangle nameRect = new(nameLeft, 6, Width - nameLeft - 8, Height - 16);
TextRenderer.DrawText(e.Graphics, RoomName, nameFont, nameRect, nameColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter);
string userCountText = RoomUserCount.ToString();
Size countSize = TextRenderer.MeasureText(e.Graphics, userCountText, userCountFont);
if(!HideUserCount)
{
int rightPad = 8;
int countX = Width - countSize.Width - rightPad;
int countY = (Height - countSize.Height) / 2;
Point userCountPoint = new(countX, countY);
TextRenderer.DrawText(e.Graphics, userCountText, userCountFont, userCountPoint, userCountColor, TextFormatFlags.Left);
}
}
protected override void OnMouseDoubleClick(MouseEventArgs e)
{
base.OnMouseDoubleClick(e);
OnRoomDoubleClicked?.Invoke(this, EventArgs.Empty);
}
protected override void OnMouseHover(EventArgs e)
{
base.OnMouseHover(e);
IsHoveredOn = true;
Invalidate();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
IsHoveredOn = false;
Invalidate();
}
}
}

View File

@ -32,17 +32,18 @@
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ChatRoom));
rtxtChatbox = new RichTextBox();
btnSend = new Button();
rtxtChat = new RichTextBox();
lblRoomName = new Label();
lvUserList = new ListView();
ilStatusIcons = new ImageList(components);
ilProfileImages = new ImageList(components);
lvUserList = new ListView();
fpnlMessages = new FlowLayoutPanel();
SuspendLayout();
//
// rtxtChatbox
//
rtxtChatbox.Location = new Point(12, 268);
rtxtChatbox.Location = new Point(12, 322);
rtxtChatbox.Name = "rtxtChatbox";
rtxtChatbox.Size = new Size(512, 54);
rtxtChatbox.Size = new Size(589, 54);
rtxtChatbox.TabIndex = 1;
rtxtChatbox.Text = "";
rtxtChatbox.KeyDown += rtxtChatbox_KeyDown;
@ -52,24 +53,13 @@
btnSend.FlatAppearance.BorderSize = 0;
btnSend.FlatStyle = FlatStyle.Flat;
btnSend.Image = Properties.Resources.SendIcon;
btnSend.Location = new Point(530, 268);
btnSend.Location = new Point(607, 322);
btnSend.Name = "btnSend";
btnSend.Size = new Size(75, 54);
btnSend.TabIndex = 2;
btnSend.UseVisualStyleBackColor = true;
btnSend.Click += btnSend_Click;
//
// rtxtChat
//
rtxtChat.Font = new Font("Segoe UI", 10F);
rtxtChat.HideSelection = false;
rtxtChat.Location = new Point(142, 43);
rtxtChat.Name = "rtxtChat";
rtxtChat.ReadOnly = true;
rtxtChat.Size = new Size(463, 219);
rtxtChat.TabIndex = 3;
rtxtChat.Text = "";
//
// lblRoomName
//
lblRoomName.AutoSize = true;
@ -82,19 +72,6 @@
lblRoomName.TabIndex = 8;
lblRoomName.Text = "Room";
//
// lvUserList
//
lvUserList.Alignment = ListViewAlignment.Left;
lvUserList.Location = new Point(12, 43);
lvUserList.MultiSelect = false;
lvUserList.Name = "lvUserList";
lvUserList.Size = new Size(124, 219);
lvUserList.SmallImageList = ilStatusIcons;
lvUserList.TabIndex = 9;
lvUserList.UseCompatibleStateImageBehavior = false;
lvUserList.View = View.SmallIcon;
lvUserList.DoubleClick += lvUserList_DoubleClick;
//
// ilStatusIcons
//
ilStatusIcons.ColorDepth = ColorDepth.Depth32Bit;
@ -105,17 +82,50 @@
ilStatusIcons.Images.SetKeyName(2, "Away");
ilStatusIcons.Images.SetKeyName(3, "DND");
//
// ilProfileImages
//
ilProfileImages.ColorDepth = ColorDepth.Depth32Bit;
ilProfileImages.ImageStream = (ImageListStreamer)resources.GetObject("ilProfileImages.ImageStream");
ilProfileImages.TransparentColor = Color.Transparent;
ilProfileImages.Images.SetKeyName(0, "DefaultPFP");
//
// lvUserList
//
lvUserList.Alignment = ListViewAlignment.Left;
lvUserList.Location = new Point(12, 43);
lvUserList.MultiSelect = false;
lvUserList.Name = "lvUserList";
lvUserList.Size = new Size(124, 273);
lvUserList.SmallImageList = ilStatusIcons;
lvUserList.TabIndex = 9;
lvUserList.UseCompatibleStateImageBehavior = false;
lvUserList.View = View.SmallIcon;
lvUserList.DoubleClick += lvUserList_DoubleClick;
//
// fpnlMessages
//
fpnlMessages.AutoScroll = true;
fpnlMessages.BackColor = Color.White;
fpnlMessages.BorderStyle = BorderStyle.Fixed3D;
fpnlMessages.FlowDirection = FlowDirection.TopDown;
fpnlMessages.Location = new Point(142, 43);
fpnlMessages.Name = "fpnlMessages";
fpnlMessages.Size = new Size(540, 273);
fpnlMessages.TabIndex = 10;
fpnlMessages.WrapContents = false;
//
// ChatRoom
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
BackColor = Color.DodgerBlue;
ClientSize = new Size(617, 334);
ClientSize = new Size(694, 388);
Controls.Add(fpnlMessages);
Controls.Add(lvUserList);
Controls.Add(lblRoomName);
Controls.Add(rtxtChat);
Controls.Add(btnSend);
Controls.Add(rtxtChatbox);
DoubleBuffered = true;
FormBorderStyle = FormBorderStyle.FixedSingle;
Icon = (Icon)resources.GetObject("$this.Icon");
MaximizeBox = false;
@ -131,9 +141,10 @@
#endregion
private RichTextBox rtxtChatbox;
private Button btnSend;
private RichTextBox rtxtChat;
private Label lblRoomName;
private ListView lvUserList;
private ImageList ilStatusIcons;
private ImageList ilProfileImages;
private ListView lvUserList;
private FlowLayoutPanel fpnlMessages;
}
}

View File

@ -1,38 +1,63 @@
using qtc_net_client_2.Services;
using qtc_net_client_2.ClientModel;
using qtc_net_client_2.Controls;
using qtc_net_client_2.Services;
using QtCNETAPI.Dtos.User;
using QtCNETAPI.Events;
using QtCNETAPI.Models;
using QtCNETAPI.Services.ApiService;
using QtCNETAPI.Services.GatewayService;
using System.Threading.Tasks;
namespace qtc_net_client_2.Forms
{
public partial class ChatRoom : Form
{
IGatewayService _gatewayService;
IApiService _apiService;
AudioService AudioService = new();
private readonly IGatewayService _gatewayService;
private readonly IApiService _apiService;
private readonly AudioService AudioService = new();
public ChatRoom(IGatewayService gatewayService, IApiService apiService)
private readonly List<User> RoomUserList = new();
private Room? Room;
public ChatRoom(IGatewayService gatewayService, IApiService apiService, Room? room = null)
{
_gatewayService = gatewayService;
_apiService = apiService;
InitializeComponent();
}
Room = room;
private void frmChat_Load(object sender, EventArgs e)
{
// subscribe to server message event
_gatewayService.OnRoomMessageReceived += _gatewayService_OnServerMessageReceived;
_gatewayService.OnRoomUserListReceived += _gatewayService_OnRoomUserListReceived;
_gatewayService.OnRoomDeleted += _gatewayService_OnRoomDeleted;
_gatewayService.OnGuestUserJoin += _gatewayService_OnGuestUserJoin;
if (_gatewayService.CurrentRoom != null) { Text = $"QtC.NET Client - Chat Room - {_gatewayService.CurrentRoom.Name}"; lblRoomName.Text = _gatewayService.CurrentRoom.Name; }
else if (_gatewayService.InLobby) { Text = $"QtC.NET Client - Chat Room - Lobby"; lblRoomName.Text = "Lobby"; }
InitializeComponent();
}
lvUserList.Clear();
private async void frmChat_Load(object sender, EventArgs e)
{
if (Room == null)
{
// join lobby
await _gatewayService.JoinRoomAsync();
Room = new Room
{
Id = "LOBBY",
Name = "Lobby"
};
}
else
{
// join selected room
await _gatewayService.JoinRoomAsync(Room);
}
// always add current user to list i guess
lvUserList.Items.Add(_apiService.CurrentUser.Username, _apiService.CurrentUser.Status);
// init ui
Text = $"QtC.NET Client - Chat Room - {Room.Name}";
lblRoomName.Text = Room.Name;
RoomUserList.Clear();
lvUserList.Items.Clear();
}
private async void frmChat_FormClosing(object sender, FormClosingEventArgs e)
@ -41,7 +66,7 @@ namespace qtc_net_client_2.Forms
_gatewayService.OnRoomMessageReceived -= _gatewayService_OnServerMessageReceived;
_gatewayService.OnRoomUserListReceived -= _gatewayService_OnRoomUserListReceived;
if (_gatewayService.CurrentRoom != null || _gatewayService.InLobby)
if (_gatewayService.CurrentRoom != null)
{
// leave any room user is in
await _gatewayService.LeaveRoomAsync();
@ -57,7 +82,7 @@ namespace qtc_net_client_2.Forms
// send it and clear text box
await _gatewayService.PostMessageAsync(message);
rtxtChatbox.Clear();
rtxtChatbox.Text = string.Empty;
AudioService.PlaySoundEffect("sndSendClick");
}
}
@ -101,11 +126,12 @@ namespace qtc_net_client_2.Forms
}
}
private void _gatewayService_OnServerMessageReceived(object? sender, EventArgs e)
private async void _gatewayService_OnServerMessageReceived(object? sender, EventArgs e)
{
var msgEventArgs = (ServerMessageEventArgs)e;
var user = RoomUserList.FirstOrDefault(e => e.Username == msgEventArgs.Message.Split(':')[0]);
AddMessage(msgEventArgs.Message);
AddMessage(msgEventArgs.Message, user?.Id);
if (!msgEventArgs.Message.Contains(_apiService.CurrentUser.Username)) AudioService.PlaySoundEffect("sndMessage");
}
@ -115,12 +141,23 @@ namespace qtc_net_client_2.Forms
if (IsHandleCreated && !IsDisposed)
{
Invoke(delegate ()
Invoke(async delegate ()
{
lvUserList.Clear();
RoomUserList.Clear();
lvUserList.Items.Clear();
foreach (var user in args.UserList)
{
lvUserList.Items.Add(user.Username, user.Status);
RoomUserList.Add(user);
// TODO - probably do this only when a message is received (requires response model change)
var pfpRes = await _apiService.GetUserProfilePic(user.Id);
if (pfpRes != null && pfpRes.Success && pfpRes.Data != null)
{
using var ms = new MemoryStream(pfpRes.Data);
using var bmp = new Bitmap(ms);
ilProfileImages.Images.Add(user.Id, bmp);
}
}
});
}
@ -128,17 +165,18 @@ namespace qtc_net_client_2.Forms
private void _gatewayService_OnGuestUserJoin(object? sender, EventArgs e)
{
var args = (GuestUserJoinEventArgs)e;
AddMessage($"[SERVER] Guest User {args.Username} Has Joined {_gatewayService.CurrentRoom?.Name}");
AddMessage($"Server: Guest User {args.Username} Has Joined {_gatewayService.CurrentRoom?.Name}");
}
private void _gatewayService_OnRoomDeleted(object? sender, EventArgs e)
{
if(IsHandleCreated && !IsDisposed)
if (IsHandleCreated && !IsDisposed)
{
Invoke(delegate ()
{
AddMessage($"[SERVER] This Room Was Deleted By An Admin.");
lvUserList.Clear();
AddMessage($"Server: This Room Was Deleted By An Admin.");
lvUserList.Items.Clear();
RoomUserList.Clear();
lvUserList.Enabled = false;
rtxtChatbox.Enabled = false;
@ -148,13 +186,28 @@ namespace qtc_net_client_2.Forms
}
private void AddMessage(string message)
private void AddMessage(string message, string? userId = null)
{
if(IsHandleCreated && !IsDisposed)
if (IsHandleCreated && !IsDisposed)
{
Invoke(delegate ()
Invoke((Delegate)delegate ()
{
rtxtChat.AppendText(message + Environment.NewLine);
var ctrl = new ChatMessageControl()
{
Username = message.Split(':')[0],
Message = message.Split(':')[1].Trim(),
Width = fpnlMessages.ClientSize.Width - SystemInformation.VerticalScrollBarWidth
};
if(ilProfileImages.Images.ContainsKey(userId))
ctrl.Avatar = ilProfileImages.Images[userId];
else ctrl.Avatar = null;
ctrl.Height = ctrl.CalculateHeight(ctrl.Width);
fpnlMessages.Controls.Add(ctrl);
fpnlMessages.VerticalScroll.Value = fpnlMessages.VerticalScroll.Maximum;
fpnlMessages.PerformLayout();
});
}
}

View File

@ -124,93 +124,218 @@
<value>
AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAA+hMAAAJNU0Z0AUkBTAIBAQQB
AAHAAQABwAEAARABAAEQAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABQAMAASADAAEBAQABIAYAASD/
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAchMAAAJNU0Z0AUkBTAIBAQQB
AAEYAQIBGAECARABAAEQAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABQAMAASADAAEBAQABIAYAASD/
AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AC4AAwYBBwM0AVQDUQGiA14B0gNaAekDYAHoA10B
0QNQAZ8DMQFNAwUBBhgAAwYBBwM0AVQDUQGiA14B0gNaAekDYAHoA10B0QNQAZ8DMQFNAwUBBhgAAwYB
BwM0AVQDUQGiA14B0gNaAekDYAHoA10B0QNQAZ8DMQFNAwUBBhgAAwYBBwM0AVQDUQGiA14B0gNaAekD
YAHoA10B0QNQAZ8DMQFNAwUBBhQAAyABLQNUAasDWwHkA1UB9QMkAfsDPAH+AzwB/gMkAfsDUwH0A2IB
4QNRAaEDHgEqEAADIAEtA1QBqwNbAeQBSwFaAUsB9QEhAVgBIQH7ARgBWAEYAf4BGAFYARgB/gEhAVgB
IQH7A1MB9ANiAeEDUQGhAx4BKhAAAyABLQNUAasDWwHkAUsCWgH1ASECWAH7ARgCWAH+ARgCWAH+ASEC
WAH7A1MB9ANiAeEDUQGhAx4BKhAAAyABLQNUAasDWwHkAksBWgH1AiEBWAH7AhgBWAH+AhgBWAH+AiEB
WAH7A1MB9ANiAeEDUQGhAx4BKgwAAxsBJQNYAb0DWgHyA0AB/gMwAf8DOQH/AzwB/wM2Af8DKgH/AyQB
/wNAAf0DXgHwA1YBsgMaASMIAAMbASUDWAG9A1oB8gEYAWABGAH+AQABVwEAAf8BAAFnAQAB/wEAAWwB
AAH/AQABYQEAAf8BAAFMAQAB/wEAAUABAAH/ATABQAEwAf0BWgFeAVoB8ANWAbIBGQEaARkBIwgAAxsB
JQNYAb0DWgHyARgCYAH+AQACVwH/AQACZwH/AQACbAH/AQACYQH/AQACTAH/AQACQAH/ATACQAH9AVoC
XgHwA1YBsgEZAhoBIwgAAxsBJQNYAb0DWgHyAhgBYAH+AgABVwH/AgABZwH/AgABbAH/AgABYQH/AgAB
TAH/AgABQAH/AjABQAH9AloBXgHwA1YBsgIZARoBIwQAAwMBBANSAaUDYAHzA0kB/wNVAf8DZQH/A3EB
/wN1Af8DcQH/A2QB/wNMAf8DMQH/AzwB/gNiAe4DUAGaAwMBBAMDAQQBUgFTAVIBpQFWAW8BVgHzAQAB
ggEAAf8BAAGZAQAB/wEAAbYBAAH/AQABzAEAAf8BAAHTAQAB/wEAAcsBAAH/AQABswEAAf8BAAGIAQAB
/wEAAVcBAAH/ARgBWAEYAf4BXwFiAV8B7gNQAZoDAwEEAwMBBAFSAlMBpQFWAm8B8wEAAoIB/wEAApkB
/wEAArYB/wEAAswB/wEAAtMB/wEAAssB/wEAArMB/wEAAogB/wEAAlcB/wEYAlgB/gFfAmIB7gNQAZoD
AwEEAwMBBAJSAVMBpQJWAW8B8wIAAYIB/wIAAZkB/wIAAbYB/wIAAcwB/wIAAdMB/wIAAcsB/wIAAbMB
/wIAAYgB/wIAAVcB/wIYAVgB/gJfAWIB7gNQAZoDAwEEAy0BRANgAegDewH+A24B/wN7Af8DhQH/A4oB
/wOMAf8DigH/A4UB/wN2Af8DVwH/AzIB/wNAAf0DXgHdAyoBPwMtAUQBYAFpAWAB6AEYAYQBGAH+AQAB
xgEAAf8BAAHcAQAB/wEAAe4BAAH/AQAB+AEAAf8BAAH7AQAB/wEAAfkBAAH/AQAB7wEAAf8BAAHUAQAB
/wEAAZwBAAH/AQABWgEAAf8BMAFAATAB/QNeAd0DKgE/Ay0BRAFgAmkB6AEYAoQB/gEAAsYB/wEAAtwB
/wEAAu4B/wEAAvgB/wEAAvsB/wEAAvkB/wEAAu8B/wEAAtQB/wEAApwB/wEAAloB/wEwAkAB/QNeAd0D
KgE/Ay0BRAJgAWkB6AIYAYQB/gIAAcYB/wIAAdwB/wIAAe4B/wIAAfgB/wIAAfsB/wIAAfkB/wIAAe8B
/wIAAdQB/wIAAZwB/wIAAVoB/wIwAUAB/QNeAd0DKgE/A04BlQN3AfgDfwH/A4UB/wOKAf8DjQH/A44B
/wOOAf8DjgH/A40B/wOJAf8DdwH/A00B/wMlAf8DWgHyA0oBiwNOAZUBQgGBAUIB+AEAAeUBAAH/AQAB
7wEAAf8BAAH4AQAB/wEAAf0BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/gEAAf8BAAH2AQAB
/wEAAdUBAAH/AQABiwEAAf8BAAFBAQAB/wNaAfIDSgGLA04BlQFCAoEB+AEAAuUB/wEAAu8B/wEAAvgB
/wEAAv0B/wEAA/8BAAP/AQAD/wEAAv4B/wEAAvYB/wEAAtUB/wEAAosB/wEAAkEB/wNaAfIDSgGLA04B
lQJCAYEB+AIAAeUB/wIAAe8B/wIAAfgB/wIAAf0B/wIAAv8CAAL/AgAC/wIAAf4B/wIAAfYB/wIAAdUB
/wIAAYsB/wIAAUEB/wNaAfIDSgGLA18B0wN+AfwDkwH/A44B/wONAf8DjgH/A44B/wOOAf8DjgH/A44B
/wONAf8DhQH/A2cB/wM0Af8DQQH5A1oBxAFbAV8BWwHTASsBsAErAfwBDgH7AQ4B/wEDAf0BAwH/AQAB
/gEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/QEAAf8BAAHvAQAB
/wEAAbkBAAH/AQABXQEAAf8DQQH5A1oBxAFbAl8B0wErArAB/AEOAvsB/wEDAv0B/wEAAv4B/wEAA/8B
AAP/AQAD/wEAA/8BAAP/AQAC/QH/AQAC7wH/AQACuQH/AQACXQH/A0EB+QNaAcQCWwFfAdMCKwGwAfwC
DgH7Af8CAwH9Af8CAAH+Af8CAAL/AgAC/wIAAv8CAAL/AgAC/wIAAf0B/wIAAe8B/wIAAbkB/wIAAV0B
/wNBAfkDWgHEA24B9QOAAf4DnwH/A5MB/wOPAf8DjgH/A44B/wOOAf8DjgH/A44B/wOOAf8DiwH/A3cB
/wNIAf8DQAH9A2IB4QFTAXYBUwH1ATwBzwE8Af4BJwH/AScB/wELAf8BCwH/AQEB/wEBAf8BAAH/AQAB
/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH5AQAB/wEAAdYBAAH/AQAB
gQEAAf8BMAFAATAB/QNiAeEBUwJ2AfUBPALPAf4BJwP/AQsD/wEBA/8BAAP/AQAD/wEAA/8BAAP/AQAD
/wEAA/8BAAL5Af8BAALWAf8BAAKBAf8BMAJAAf0DYgHhAlMBdgH1AjwBzwH+AicC/wILAv8CAQL/AgAC
/wIAAv8CAAL/AgAC/wIAAv8CAAL/AgAB+QH/AgAB1gH/AgABgQH/AjABQAH9A2IB4QNtAfYDgAH+A6sB
/wOZAf8DkAH/A44B/wOOAf8DjgH/A44B/wOOAf8DjgH/A40B/wN/Af8DVQH/A0AB/QNeAeIBSAF6AUgB
9gFfAc8BXwH+AUIB/wFCAf8BGQH/ARkB/wEEAf8BBAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB
/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/QEAAf8BAAHkAQAB/wEAAZgBAAH/ATABQAEwAf0DXgHiAUgC
egH2AV8CzwH+AUID/wEZA/8BBAP/AQAD/wEAA/8BAAP/AQAD/wEAA/8BAAP/AQAC/QH/AQAC5AH/AQAC
mAH/ATACQAH9A14B4gJIAXoB9gJfAc8B/gJCAv8CGQL/AgQC/wIAAv8CAAL/AgAC/wIAAv8CAAL/AgAC
/wIAAf0B/wIAAeQB/wIAAZgB/wIwAUAB/QNeAeIDYQHWA34B/AO4Af8DowH/A5MB/wOOAf8DjgH/A44B
/wOOAf8DjgH/A44B/wONAf8DggH/A1wB/wNNAfoDWgHHAVwBYQFcAdYBZAG0AWQB/AFfAf8BXwH/AS8B
/wEvAf8BDAH/AQwB/wEBAf8BAQH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB
/wEAAf4BAAH/AQAB6gEAAf8BAAGlAQAB/wEsAU0BLAH6A1oBxwFcAmEB1gFkArQB/AFfA/8BLwP/AQwD
/wEBA/8BAAP/AQAD/wEAA/8BAAP/AQAD/wEAAv4B/wEAAuoB/wEAAqUB/wEsAk0B+gNaAccCXAFhAdYC
ZAG0AfwCXwL/Ai8C/wIMAv8CAQL/AgAC/wIAAv8CAAL/AgAC/wIAAv8CAAH+Af8CAAHqAf8CAAGlAf8C
LAFNAfoDWgHHA1ABmgOIAfkDxQH/A7IB/wOcAf8DkQH/A44B/wOOAf8DjgH/A44B/wOPAf8DjgH/A4MB
/wNgAf8DWgHyA0wBkANQAZoBagGRAWoB+QF8Af8BfAH/AVEB/wFRAf8BHwH/AR8B/wEHAf8BBwH/AQEB
/wEBAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAgH/AQIB/wECAf4BAgH/AQAB6wEAAf8BAAGtAQAB
/wFaAWsBWgHyA0wBkANQAZoBagKRAfkBfAP/AVED/wEfA/8BBwP/AQED/wEAA/8BAAP/AQAD/wECA/8B
AgL+Af8BAALrAf8BAAKtAf8BWgJrAfIDTAGQA1ABmgJqAZEB+QJ8Av8CUQL/Ah8C/wIHAv8CAQL/AgAC
/wIAAv8CAAL/AgIC/wICAf4B/wIAAesB/wIAAa0B/wJaAWsB8gNMAZADLwFJA2wB6wOgAf4DxgH/A64B
/wOcAf8DkwH/A5AB/wOPAf8DkAH/A5MB/wOTAf8DhQH/A04B/QNgAeADLQFFAy8BSQNsAesBgAHPAYAB
/gF/Af8BfwH/AUkB/wFJAf8BHwH/AR8B/wEMAf8BDAH/AQUB/wEFAf8BAwH/AQMB/wEFAf8BBQH/AQoB
/wEKAf8BCgH+AQoB/wEBAe0BAQH/ATABtgEwAf0BYAFmAWAB4AMtAUUDLwFJA2wB6wGAAs8B/gF/A/8B
SQP/AR8D/wEMA/8BBQP/AQMD/wEFA/8BCgP/AQoC/gH/AQEC7QH/ATACtgH9AWACZgHgAy0BRQMvAUkD
bAHrAoABzwH+An8C/wJJAv8CHwL/AgwC/wIFAv8CAwL/AgUC/wIKAv8CCgH+Af8CAQHtAf8CMAG2Af0C
YAFmAeADLQFFAwMBBANWAa4DcAH1A9kB/wPLAf8DtwH/A6cB/wOdAf8DmgH/A5wB/wOfAf8DmwH/A4kB
/wNoAfADUgGjAwMBBAMDAQQDVgGuAW4BdgFuAfUBqAH/AagB/wGJAf8BiQH/AVwB/wFcAf8BNwH/ATcB
/wEiAf8BIgH/ARsB/wEbAf8BHwH/AR8B/wEmAf8BJgH/AR0B/wEdAf8BBQHzAQUB/wFaAWgBWgHwA1IB
owMDAQQDAwEEA1YBrgFuAnYB9QGoA/8BiQP/AVwD/wE3A/8BIgP/ARsD/wEfA/8BJgP/AR0D/wEFAvMB
/wFaAmgB8ANSAaMDAwEEAwMBBANWAa4CbgF2AfUCqAL/AokC/wJcAv8CNwL/AiIC/wIbAv8CHwL/AiYC
/wIdAv8CBQHzAf8CWgFoAfADUgGjAwMBBAQAAxwBJwNdAccDdwH2A68B/gPXAf8DzAH/A8IB/wO7Af8D
twH/A7EB/wOAAf4DaAH0A1kBvAMbASYIAAMcAScDXQHHAXIBegFyAfYBhwHPAYcB/gGlAf8BpQH/AYsB
/wGLAf8BdAH/AXQB/wFmAf8BZgH/AVwB/wFcAf8BTgH/AU4B/wFIAc8BSAH+AVMBdwFTAfQBVwFZAVcB
vAMbASYIAAMcAScDXQHHAXICegH2AYcCzwH+AaUD/wGLA/8BdAP/AWYD/wFcA/8BTgP/AUgCzwH+AVMC
dwH0AVcCWQG8AxsBJggAAxwBJwNdAccCcgF6AfYChwHPAf4CpQL/AosC/wJ0Av8CZgL/AlwC/wJOAv8C
SAHPAf4CUwF3AfQCVwFZAbwDGwEmDAADIQEwA1kBtgNnAe4DkwH6A74B/QPUAf8DzAH/A74B/QOEAfkD
bAHrA1UBrAMfASwQAAMhATADWQG2AWUBaQFlAe4BfQGfAX0B+gGuAb4BrgH9AZ8B/wGfAf8BjAH/AYwB
/wFeAb4BXgH9AWgBkQFoAfkBYQFsAWEB6wNVAawDHwEsEAADIQEwA1kBtgFlAmkB7gF9Ap8B+gGuAr4B
/QGfA/8BjAP/AV4CvgH9AWgCkQH5AWECbAHrA1UBrAMfASwQAAMhATADWQG2AmUBaQHuAn0BnwH6Aq4B
vgH9Ap8C/wKMAv8CXgG+Af0CaAGRAfkCYQFsAesDVQGsAx8BLBQAAwYBBwM2AVgDVQGsA2YB5QOgAfwD
kwH7A2UB4gNTAacDMwFRAwYBBxgAAwYBBwM2AVgDVQGsA2YB5QF+AbQBfgH8AW0BngFtAfsDZQHiA1MB
pwMzAVEDBgEHGAADBgEHAzYBWANVAawDZgHlAX4CtAH8AW0CngH7A2UB4gNTAacDMwFRAwYBBxgAAwYB
BwM2AVgDVQGsA2YB5QJ+AbQB/AJtAZ4B+wNlAeIDUwGnAzMBUQMGAQcMAAFCAU0BPgcAAT4DAAEoAwAB
QAMAASADAAEBAQABAQYAAQEWAAP/gQAB4AEHAeABBwHgAQcB4AEHAcABAwHAAQMBwAEDAcABAwGAAQEB
gAEBAYABAQGAAQFQAAGAAQEBgAEBAYABAQGAAQEBwAEDAcABAwHAAQMBwAEDAeABBwHgAQcB4AEHAeAB
Bws=
YAHoA10B0QNQAZ8DMQFNAwUBBhQAAyABLQNUAasDWwHkA1oB9QMkAfsDZwH+A2cB/gMkAfsDUwH0A2IB
4QNRAaEDHgEqEAADIAEtA1QBqwNbAeQDWgH1ASEBXgEhAfsBQwGAAUMB/gFDAYABQwH+ASEBXgEhAfsD
UwH0A2IB4QNRAaEDHgEqEAADIAEtA1QBqwNbAeQDWgH1ASECXgH7AUMCgAH+AUMCgAH+ASECXgH7A1MB
9ANiAeEDUQGhAx4BKhAAAyABLQNUAasDWwHkA1oB9QIhAV4B+wJDAYAB/gJDAYAB/gIhAV4B+wNTAfQD
YgHhA1EBoQMeASoMAAMbASUDWAG9A1oB8gNrAf4DMAH/AzkB/wM8Af8DNgH/AyoB/wMkAf8DQAH9A14B
8ANWAbIDGgEjCAADGwElA1gBvQNaAfIBQwGAAUMB/gEAAVcBAAH/AQABZwEAAf8BAAFsAQAB/wEAAWEB
AAH/AQABTAEAAf8BAAFAAQAB/wNAAf0DXgHwA1YBsgEZARoBGQEjCAADGwElA1gBvQNaAfIBQwKAAf4B
AAJXAf8BAAJnAf8BAAJsAf8BAAJhAf8BAAJMAf8BAAJAAf8DQAH9A14B8ANWAbIBGQIaASMIAAMbASUD
WAG9A1oB8gJDAYAB/gIAAVcB/wIAAWcB/wIAAWwB/wIAAWEB/wIAAUwB/wIAAUAB/wNAAf0DXgHwA1YB
sgIZARoBIwQAAwMBBANSAaUDYAHzA0kB/wNVAf8DZQH/A3EB/wN1Af8DcQH/A2QB/wNMAf8DMQH/A2cB
/gNiAe4DUAGaAwMBBAMDAQQBUgFTAVIBpQFgAW8BYAHzAQABggEAAf8BAAGZAQAB/wEAAbYBAAH/AQAB
zAEAAf8BAAHTAQAB/wEAAcsBAAH/AQABswEAAf8BAAGIAQAB/wEAAVcBAAH/AUMBgAFDAf4DYgHuA1AB
mgMDAQQDAwEEAVICUwGlAWACbwHzAQACggH/AQACmQH/AQACtgH/AQACzAH/AQAC0wH/AQACywH/AQAC
swH/AQACiAH/AQACVwH/AUMCgAH+A2IB7gNQAZoDAwEEAwMBBAJSAVMBpQJgAW8B8wIAAYIB/wIAAZkB
/wIAAbYB/wIAAcwB/wIAAdMB/wIAAcsB/wIAAbMB/wIAAYgB/wIAAVcB/wJDAYAB/gNiAe4DUAGaAwMB
BAMtAUQDYAHoA4AB/gNuAf8DewH/A4UB/wOKAf8DjAH/A4oB/wOFAf8DdgH/A1cB/wMyAf8DQAH9A14B
3QMqAT8DLQFEAWABaQFgAegBQwGAAUMB/gEAAcYBAAH/AQAB3AEAAf8BAAHuAQAB/wEAAfgBAAH/AQAB
+wEAAf8BAAH5AQAB/wEAAe8BAAH/AQAB1AEAAf8BAAGcAQAB/wEAAVoBAAH/A0AB/QNeAd0DKgE/Ay0B
RAFgAmkB6AFDAoAB/gEAAsYB/wEAAtwB/wEAAu4B/wEAAvgB/wEAAvsB/wEAAvkB/wEAAu8B/wEAAtQB
/wEAApwB/wEAAloB/wNAAf0DXgHdAyoBPwMtAUQCYAFpAegCQwGAAf4CAAHGAf8CAAHcAf8CAAHuAf8C
AAH4Af8CAAH7Af8CAAH5Af8CAAHvAf8CAAHUAf8CAAGcAf8CAAFaAf8DQAH9A14B3QMqAT8DTgGVA3cB
+AN/Af8DhQH/A4oB/wONAf8DjgH/A44B/wOOAf8DjQH/A4kB/wN3Af8DTQH/AyUB/wNaAfIDSgGLA04B
lQFcAXwBXAH4AQAB5QEAAf8BAAHvAQAB/wEAAfgBAAH/AQAB/QEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB
/wEAAf8BAAH+AQAB/wEAAfYBAAH/AQAB1QEAAf8BAAGLAQAB/wEAAUEBAAH/A1oB8gNKAYsDTgGVAVwC
fAH4AQAC5QH/AQAC7wH/AQAC+AH/AQAC/QH/AQAD/wEAA/8BAAP/AQAC/gH/AQAC9gH/AQAC1QH/AQAC
iwH/AQACQQH/A1oB8gNKAYsDTgGVAlwBfAH4AgAB5QH/AgAB7wH/AgAB+AH/AgAB/QH/AgAC/wIAAv8C
AAL/AgAB/gH/AgAB9gH/AgAB1QH/AgABiwH/AgABQQH/A1oB8gNKAYsDXwHTA34B/AOTAf8DjgH/A40B
/wOOAf8DjgH/A44B/wOOAf8DjgH/A40B/wOFAf8DZwH/AzQB/wNBAfkDWgHEAVsBXwFbAdMBKwF+ASsB
/AEOAfsBDgH/AQMB/QEDAf8BAAH+AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB
/wEAAf8BAAH9AQAB/wEAAe8BAAH/AQABuQEAAf8BAAFdAQAB/wNBAfkDWgHEAVsCXwHTASsCfgH8AQ4C
+wH/AQMC/QH/AQAC/gH/AQAD/wEAA/8BAAP/AQAD/wEAA/8BAAL9Af8BAALvAf8BAAK5Af8BAAJdAf8D
QQH5A1oBxAJbAV8B0wIrAX4B/AIOAfsB/wIDAf0B/wIAAf4B/wIAAv8CAAL/AgAC/wIAAv8CAAL/AgAB
/QH/AgAB7wH/AgABuQH/AgABXQH/A0EB+QNaAcQDbgH1A4AB/gOfAf8DkwH/A48B/wOOAf8DjgH/A44B
/wOOAf8DjgH/A44B/wOLAf8DdwH/A0gB/wNAAf0DYgHhAVoBbgFaAfUBZwGAAWcB/gEnAf8BJwH/AQsB
/wELAf8BAQH/AQEB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB
/wEAAfkBAAH/AQAB1gEAAf8BAAGBAQAB/wNAAf0DYgHhAVoCbgH1AWcCgAH+AScD/wELA/8BAQP/AQAD
/wEAA/8BAAP/AQAD/wEAA/8BAAP/AQAC+QH/AQAC1gH/AQACgQH/A0AB/QNiAeECWgFuAfUCZwGAAf4C
JwL/AgsC/wIBAv8CAAL/AgAC/wIAAv8CAAL/AgAC/wIAAv8CAAH5Af8CAAHWAf8CAAGBAf8DQAH9A2IB
4QNjAfYDgAH+A6sB/wOZAf8DkAH/A44B/wOOAf8DjgH/A44B/wOOAf8DjgH/A40B/wN/Af8DVQH/A0AB
/QNeAeIBSAFjAUgB9gOAAf4BQgH/AUIB/wEZAf8BGQH/AQQB/wEEAf8BAAH/AQAB/wEAAf8BAAH/AQAB
/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH9AQAB/wEAAeQBAAH/AQABmAEAAf8DQAH9A14B
4gFIAmMB9gOAAf4BQgP/ARkD/wEEA/8BAAP/AQAD/wEAA/8BAAP/AQAD/wEAA/8BAAL9Af8BAALkAf8B
AAKYAf8DQAH9A14B4gJIAWMB9gOAAf4CQgL/AhkC/wIEAv8CAAL/AgAC/wIAAv8CAAL/AgAC/wIAAv8C
AAH9Af8CAAHkAf8CAAGYAf8DQAH9A14B4gNhAdYDfgH8A7gB/wOjAf8DkwH/A44B/wOOAf8DjgH/A44B
/wOOAf8DjgH/A40B/wOCAf8DXAH/A00B+gNaAccBXAFhAVwB1gFkAX4BZAH8AV8B/wFfAf8BLwH/AS8B
/wEMAf8BDAH/AQEB/wEBAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB
/gEAAf8BAAHqAQAB/wEAAaUBAAH/A00B+gNaAccBXAJhAdYBZAJ+AfwBXwP/AS8D/wEMA/8BAQP/AQAD
/wEAA/8BAAP/AQAD/wEAA/8BAAL+Af8BAALqAf8BAAKlAf8DTQH6A1oBxwJcAWEB1gJkAX4B/AJfAv8C
LwL/AgwC/wIBAv8CAAL/AgAC/wIAAv8CAAL/AgAC/wIAAf4B/wIAAeoB/wIAAaUB/wNNAfoDWgHHA1AB
mgNqAfkDxQH/A7IB/wOcAf8DkQH/A44B/wOOAf8DjgH/A44B/wOPAf8DjgH/A4MB/wNgAf8DWgHyA0wB
kANQAZoDagH5AXwB/wF8Af8BUQH/AVEB/wEfAf8BHwH/AQcB/wEHAf8BAQH/AQEB/wEAAf8BAAH/AQAB
/wEAAf8BAAH/AQAB/wECAf8BAgH/AQIB/gECAf8BAAHrAQAB/wEAAa0BAAH/AVoBawFaAfIDTAGQA1AB
mgNqAfkBfAP/AVED/wEfA/8BBwP/AQED/wEAA/8BAAP/AQAD/wECA/8BAgL+Af8BAALrAf8BAAKtAf8B
WgJrAfIDTAGQA1ABmgNqAfkCfAL/AlEC/wIfAv8CBwL/AgEC/wIAAv8CAAL/AgAC/wICAv8CAgH+Af8C
AAHrAf8CAAGtAf8CWgFrAfIDTAGQAy8BSQNsAesDgAH+A8YB/wOuAf8DnAH/A5MB/wOQAf8DjwH/A5AB
/wOTAf8DkwH/A4UB/wNAAf0DYAHgAy0BRQMvAUkDbAHrA4AB/gF/Af8BfwH/AUkB/wFJAf8BHwH/AR8B
/wEMAf8BDAH/AQUB/wEFAf8BAwH/AQMB/wEFAf8BBQH/AQoB/wEKAf8BCgH+AQoB/wEBAe0BAQH/AUAB
tgFAAf0BYAFmAWAB4AMtAUUDLwFJA2wB6wOAAf4BfwP/AUkD/wEfA/8BDAP/AQUD/wEDA/8BBQP/AQoD
/wEKAv4B/wEBAu0B/wFAArYB/QFgAmYB4AMtAUUDLwFJA2wB6wOAAf4CfwL/AkkC/wIfAv8CDAL/AgUC
/wIDAv8CBQL/AgoC/wIKAf4B/wIBAe0B/wJAAbYB/QJgAWYB4AMtAUUDAwEEA1YBrgNuAfUD2QH/A8sB
/wO3Af8DpwH/A50B/wOaAf8DnAH/A58B/wObAf8DiQH/A2gB8ANSAaMDAwEEAwMBBANWAa4DbgH1AagB
/wGoAf8BiQH/AYkB/wFcAf8BXAH/ATcB/wE3Af8BIgH/ASIB/wEbAf8BGwH/AR8B/wEfAf8BJgH/ASYB
/wEdAf8BHQH/AQUB8wEFAf8BXgFoAV4B8ANSAaMDAwEEAwMBBANWAa4DbgH1AagD/wGJA/8BXAP/ATcD
/wEiA/8BGwP/AR8D/wEmA/8BHQP/AQUC8wH/AV4CaAHwA1IBowMDAQQDAwEEA1YBrgNuAfUCqAL/AokC
/wJcAv8CNwL/AiIC/wIbAv8CHwL/AiYC/wIdAv8CBQHzAf8CXgFoAfADUgGjAwMBBAQAAxwBJwNdAccD
YwH2A4AB/gPXAf8DzAH/A8IB/wO7Af8DtwH/A7EB/wOAAf4DaAH0A1kBvAMbASYIAAMcAScDXQHHA2MB
9gOAAf4BpQH/AaUB/wGLAf8BiwH/AXQB/wF0Af8BZgH/AWYB/wFcAf8BXAH/AU4B/wFOAf8BcwGAAXMB
/gFTAWgBUwH0AVcBWQFXAbwDGwEmCAADHAEnA10BxwNjAfYDgAH+AaUD/wGLA/8BdAP/AWYD/wFcA/8B
TgP/AXMCgAH+AVMCaAH0AVcCWQG8AxsBJggAAxwBJwNdAccDYwH2A4AB/gKlAv8CiwL/AnQC/wJmAv8C
XAL/Ak4C/wJzAYAB/gJTAWgB9AJXAVkBvAMbASYMAAMhATADWQG2A2IB7gN9AfoDvgH9A9QB/wPMAf8D
vgH9A2oB+QNsAesDVQGsAx8BLBAAAyEBMANZAbYDYgHuA30B+gGuAb4BrgH9AZ8B/wGfAf8BjAH/AYwB
/wFAAb4BQAH9AWgBagFoAfkBYQFsAWEB6wNVAawDHwEsEAADIQEwA1kBtgNiAe4DfQH6Aa4CvgH9AZ8D
/wGMA/8BQAK+Af0BaAJqAfkBYQJsAesDVQGsAx8BLBAAAyEBMANZAbYDYgHuA30B+gKuAb4B/QKfAv8C
jAL/AkABvgH9AmgBagH5AmEBbAHrA1UBrAMfASwUAAMGAQcDNgFYA1UBrANmAeUDfgH8A18B+wNlAeID
UwGnAzMBUQMGAQcYAAMGAQcDNgFYA1UBrANmAeUDfgH8AV8BZwFfAfsDZQHiA1MBpwMzAVEDBgEHGAAD
BgEHAzYBWANVAawDZgHlA34B/AFfAmcB+wNlAeIDUwGnAzMBUQMGAQcYAAMGAQcDNgFYA1UBrANmAeUD
fgH8Al8BZwH7A2UB4gNTAacDMwFRAwYBBwwAAUIBTQE+BwABPgMAASgDAAFAAwABIAMAAQEBAAEBBgAB
ARYAA/+BAAHgAQcB4AEHAeABBwHgAQcBwAEDAcABAwHAAQMBwAEDAYABAQGAAQEBgAEBAYABAVAAAYAB
AQGAAQEBgAEBAYABAQHAAQMBwAEDAcABAwHAAQMB4AEHAeABBwHgAQcB4AEHCw==
</value>
</data>
<metadata name="ilProfileImages.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>132, 12</value>
</metadata>
<data name="ilProfileImages.ImageStream" mimetype="application/x-microsoft.net.object.binary.base64">
<value>
AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAlhsAAAJNU0Z0AUkBTAMBAQAB
QAEBAUABAQEgAQABIAEABP8BIQEACP8BQgFNATYHAAE2AwABKAMAAYADAAEgAwABAQEAASAGAAFAEgAC
RwFGAYACRwFGAYACRwFGAYABRwJGAYABRwJGAYACRwFGAYACRwFGAYABRwJGAYABRwJGAYABRwJGAYAD
RgGAAkcBRgGAAkcBRgGAAkcBRgGAAkcBRgGAAkcBRgGAAkcBRgGAAkcBRgGAAkcBRgGAAkcBRgGAAkcB
RgGAAkcBRgGAA0YBgAFHAkYBgAFHAkYBgAFHAkYBgAFHAkYBgAFHAkYBgAJHAUYBgAJHAUYBgAJHAUYB
gAMqAUD/AIEAAf8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRgEBAv8BRwEBAv8BSAEAAf8B7QFGAQEB
/wHbAUMBAgH/AZEBNgEBAf8BRgEpAQAB/wF1AVABAQH/AaMBdwECAf8BzAGQAQkB/wH0AagBEAH/AfkB
rQEIAf8B/gGxAQAB/wH3Aa4BBgH/Ae8BqwEMAf8BygGOAQcB/wGlAXABAgH/AXABTgEBAf8BOwEsAQAB
/wFZAScBAAH/AXcBIgEAAf8BuwE0AQIB/wH+AUYBBAL/AUcBAwL/AUcBAQL/AUcBAQL/AUcBAQH/AkcB
RgGA/wCBAAH/AUcBAQL/AUcBAQL/AUcBAQL/AUYBAgL/AUYBAwH/AfsBRwEBAf8B9wFIAQAB/wHaAVAB
AQH/Ab0BWAEBAf8BrgFjAQEB/wGgAW8BAAH/AbgBggEBAf8B0QGWAQEB/wHkAaMBBQH/AfgBrwEJAf8B
+wGxAQUC/wGzAQEB/wH7AbEBBAH/AfcBsAEIAf8B5AGiAQQB/wHRAZQBAQH/AbcBgwECAf8BnQFyAQIB
/wGDAVEBAQH/AWgBMQEAAf8BlAEzAQEB/wHBATYBAwH/AeABPwECAv8BSAEBAv8BRwEBAv8BRwEBAf8C
RwFGAYD/AIEAAf8BRwEBAv8BRwEBAv8BRwEBAv8BRgEDAv8BRQEEAf8B9wFGAQIB/wHvAUcBAAH/AccB
WgEAAf8BnwFtAQAB/wHMAZEBAAH/AfkBtAEAAf8B/AG1AQAC/wG1AQAB/wH9AbYBAQH/AfsBtgEBAf8B
/QG1AQEC/wG0AQEC/wG0AQIC/wG0AQMB/wH+AbYBAgH/Af0BtwEAAf8B/gG3AQIC/wG3AQQB/wGsAXwB
AgH/AVkBQAEAAf8BbgEzAQEB/wGDASUBAQH/AcEBNwEBAf8B/gFIAQAC/wFIAQEC/wFHAQEB/wJHAUYB
gP8AgQAB/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQIC/wFHAQIB/wHyAUwBAQH/AeYBUgEAAf8B2gFxAQAB
/wHPAZABAAH/AeYBogEAAf8B/AG1AQEB/wH+AbUBAQL/AbUBAQH/Af4BtQEBAf8B/QG2AQEB/wH+AbUB
AQL/AbUBAQL/AbUBAgL/AbUBAgL/AbUBAQH/Af4BtgEBAf8B/QG0AQEB/wH7AbIBAgH/AdQBmAEDAf8B
rAF/AQMB/wGHAVUBAgH/AWMBKwEBAf8BrwE5AQEB/wH8AUgBAQH/Af4BRwEBAv8BRwEBAf8CRwFGAYD/
AIEAAf8BRwEBAv8BRwEBAv8BRwEBAv8BSAEBAv8BSQEAAf8B7gFTAQAB/wHcAVwBAAH/Ae4BiAEAAv8B
swEAAv8BtAEBAv8BtQEBAv8BtQEBAv8BtQEBAv8BtQEBAv8BtQEBAv8BtQEBAv8BtQEBAv8BtQEBAv8B
tQEBAv8BtQEBAv8BtQEBAf8B+wGxAQEB/wH3AawBAAH/AfsBtQEDAv8BvgEGAf8BoQF3AQQB/wFCATAB
AQH/AZ4BPAECAf8B+gFHAQIB/wH9AUcBAgL/AUcBAQH/AkcBRgGA/wCBAAH/AUcBAQL/AUcBAQL/AUcB
AQL/AUgBAQL/AUkBAAH/AfYBZAEQAf8B7gF/ASEB/wH2AZoBEAL/AbUBAAL/AbUBAQL/AbUBAQL/AbUB
AgL/AbUBAgL/AbUBAgL/AbUBAQL/AbUBAQL/AbUBAQL/AbUBAQL/AbUBAQL/AbUBAQL/AbUBAQH/Af0B
swEBAf8B+wGxAQEB/wH9AbUBAwL/AboBBQH/AaQBdwEDAf8BSQE0AQEB/wGjAT0BAgH/Af0BRgEDAf8B
/gFHAQIC/wFHAQEB/wJHAUYBgP8AgQAB/wFHAQEC/wFHAQEC/wFHAQEC/wFIAQEB/wH+AUgBAAL/AXUB
IQL/AaIBQQL/AawBIQL/AbYBAAL/AbYBAQL/AbUBAQL/AbUBAgL/AbQBAwL/AbUBAgL/AbUBAQL/AbUB
AQL/AbUBAQL/AbUBAQL/AbUBAQL/AbUBAQL/AbUBAQL/AbUBAQL/AbUBAQL/AbYBAwL/AbYBBAH/AagB
dwECAf8BUAE3AQAB/wGoAT4BAgL/AUUBBAL/AUYBAwL/AUcBAQH/AkcBRgGA/wCBAAH/AUcBAQL/AUcB
AQL/AUcBAQL/AUcBAQL/AUgBAQL/AV8BEwL/AXcBJgL/AZwBKAL/AcIBKgL/AbwBFQL/AbYBAQL/AbUB
AQL/AbUBAgL/AbUBAgL/AbUBAQL/AbUBAQL/AbUBAQL/AbUBAQL/AbUBAQL/AbUBAgL/AbUBAgL/AbUB
AQL/AbYBAQH/Af4BtgEBAf8B/QG2AQIB/wG9AXkBAQH/AX4BPQEAAf8BvgFCAQEC/wFHAQIC/wFHAQIC
/wFHAQEB/wJHAUYBgP8AgQAB/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFJAQYC/wFLAQoC
/wGMAS8C/wHNAVMC/wHCASoC/wG2AQAC/wG2AQEC/wG1AQEC/wG1AQEC/wG1AQEC/wG1AQEC/wG1AQEC
/wG1AQEC/wG1AQEC/wG1AQIC/wG0AQMC/wG1AQIC/wG2AQAB/wH9AbYBAAH/AfoBtQEAAf8B0wF8AQAB
/wGsAUMBAAH/AdUBRgEAAf8B/gFIAQAC/wFIAQEC/wFHAQEB/wJHAUYBgP8AgQAB/wFHAQEC/wFHAQEC
/wFHAQEC/wFHAQEC/wFGAQIB/wH+AUgBAwH/Af0BSQEFAf8B7wFrARwB/wHhAY0BNAH/AfABrQE7Av8B
zgFDAv8BwQEjAv8BtAEEAv8BtQECAv8BtgEBAv8BtQEBAv8BtQEBAv8BtQEBAv8BtgEBAf8B/gG0AQEB
/wH+AbMBAgH/Af4BtwEJAv8BuwEQAf8B/gG0AQ0B/wH9Aa0BCgH/AekBeAEFAf8B1gFDAQAB/wHqAUYB
AAL/AUgBAAL/AUgBAQL/AUcBAQH/AkcBRgGA/wCBAAH/AUcBAQL/AUcBAQL/AUcBAQL/AUYBAgL/AUUB
AgH/Af0BRgEBAf8B+gFHAQAB/wHfAUoBCgH/AcMBTAEUAf8B4QGZAU0C/wHlAYYC/wHMAUYC/wGzAQYC
/wG1AQMC/wG2AQAC/wG2AQEC/wG1AQEC/wG2AQEC/wG2AQAB/wH+AbQBAAH/AfwBsgEAAf8B/gG5ARAC
/wG/ASAC/wGyARoC/wGkARQC/wF0AQoC/wFDAQAC/wFGAQAC/wFIAQAC/wFIAQEC/wFHAQEB/wJHAUYB
gP8AgQAB/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFGAQIB/wH+AUcBAQH/Af0BRwEBAf8B7wFHAQYB
/wHhAUgBCwH/AfABcAEnAv8BmAFDAf8B/gGgATwB/wH9AagBNAH/Af4BugFCAv8BzAFQAv8BzAFOAv8B
ywFNAv8ByAFHAv8BxgFCAf8B/gHBAT8B/wH+Ab0BPAH/Af4BoQEnAv8BhgESAv8BfQEOAv8BdQELAv8B
XQEGAv8BRQEBAv8BRgEBAv8BSAEBAv8BRwEBAv8BRwEBAf8CRwFGAYD/AIEAAf8BRwEBAv8BRwEBAv8B
RwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRQECAv8BQwECAv8BRwEBAv8BSwEAAf8B/QF0ATEB
/wH7AZ0BYgH/Af0BwAGBAv8B4gGgAv8B4gGcAv8B4QGYAv8B2wGOAv8B1QGEAv8BzgF+Av8BxwF3Av8B
igE9Av8BTAEDAv8BSQEDAv8BRgECAv8BRwECAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAf8C
RwFGAYD/AIEAAf8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAf8B/gFGAQIB
/wH+AUUBAwH/Af4BSAECAv8BSwEAAf8B+QFdARkB/wHyAW8BMwH/Ac0BewFBAf8BpwGHAVAB/wGkAYgB
TgH/AaABigFMAf8BowGGAUoB/wGnAYMBSQH/AbcBfgFCAf8ByAF5ATwB/wHjAWEBHwL/AUoBAgL/AUgB
AgL/AUcBAgL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQH/AkcBRgGA/wCBAAH/AUcB
AQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQH/Af4BRwEDAf8B/AFGAQQB/wH+AUgB
AgL/AUoBAAH/AfQBRQECAf8B6QFAAQMB/wGcATYBAgH/AU8BLAEAAf8BSAEvAQAB/wFBATIBAAH/AUgB
MQEHAf8BTgEwAQ0B/wFvAS0BBwH/AZABKgEAAf8ByAE5AQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC
/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEB/wJHAUYBgP8AgQAB/wFHAQEC/wFHAQEC/wFHAQEC
/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEB/wH+AUcBAgH/Af4BRwECAf8B/gFGAQEC/wFFAQEB/wHhAU0B
AQH/AcMBVAECAf8BtQFhAQEB/wGnAW8BAAH/AaMBcAEAAf8BnwFxAQAB/wGjAXIBAwH/AacBcgEHAf8B
hwFPAQMB/wFoASwBAAH/AaABNQEAAf8B2AE/AQEB/wHrAUMBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcB
AQL/AUcBAQL/AUcBAQL/AUcBAQH/AkcBRgGA/wCBAAH/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcB
AQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAAL/AUQBAQL/AUABAQH/Ac4BVAEBAf8BnQFoAQAB/wHOAY0B
AAL/AbEBAAH/Af4BsQEAAf8B/AGwAQAB/wH+AbIBAAL/AbQBAAH/AaABcQEAAf8BQAEtAQAB/wF4ATIB
AAH/AbABNwEAAf8B2AE/AQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEB
/wJHAUYBgP8AgQAB/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQIC
/wFGAQIB/wH2AUUBAQH/Ae0BRQEBAf8B3gFqAQEB/wHOAZABAgH/AecBogEBAv8BtAEAAf8B/gGzAQEB
/wH+AbIBAgH/Af4BtAEDAv8BtQEDAf8BzgGRAQMB/wGdAWwBAgH/AZMBSwEBAf8BiQErAQAB/wHEATkB
AQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQH/AkcBRgGA/wCBAAH/AUcB
AQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUYBAwL/AUUBBAH/Ae0BRwECAf8B
2wFJAQAB/wHtAYABAgL/AbcBBAL/AbcBAgL/AbcBAAL/AbYBAgL/AbQBBAL/AbUBBQL/AbYBBgH/Af0B
sQEFAf8B+gGrAQQB/wGuAWUBAgH/AWIBHgEAAf8BsQEzAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC
/wFHAQEC/wFHAQEC/wFHAQEB/wJHAUYBgP8AgQAB/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC
/wFHAQEC/wFHAQEC/wFHAQIC/wFHAQIB/wHqAUkBAQH/AdYBSwEAAf8B6wGAAQMC/wG1AQYC/wG2AQMC
/wG2AQEC/wG1AQIC/wG1AQMC/wG1AQMC/wG2AQQB/wH+AbQBAwH/Af0BsgECAf8BrgFrAQEB/wFfASQB
AAH/Aa8BNQEBAv8BRwECAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAf8CRwFGAYD/
AIEAAf8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BSAEBAf8B/gFIAQAB
/wHoAUsBAAH/AdEBTQEAAf8B6AGAAQQC/wGzAQcC/wG0AQQC/wG1AQEC/wG1AQEC/wG1AQEC/wG1AQEC
/wG1AQEC/wG3AQEC/wG4AQAB/wGtAXEBAAH/AVsBKQEAAf8BrQE4AQEC/wFGAQIC/wFHAQIC/wFHAQEC
/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEB/wJHAUYBgP8AgQAB/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC
/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFIAQEB/wHzAUoBAAH/AecBTQEAAf8B8wGGAQ4C/wG/ARwC
/wG6AQ4B/wH+AbYBAQL/AbYBAQL/AbUBAQL/AbUBAQL/AbUBAQL/AbUBAQL/AbUBAQH/AcEBcQEAAf8B
gwEuAQAB/wHBAToBAQL/AUcBAgL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQH/AkcB
RgGA/wCBAAH/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcB
AQH/Af4BSgEBAf8B/QFNAQAB/wH+AYwBGQL/AcoBMQH/Af4BwQEZAf8B/QG3AQAB/wH+AbYBAQL/AbUB
AQL/AbUBAQL/AbUBAQL/AbQBAQL/AbIBAQH/AdUBcgEBAf8BqwEyAQAB/wHVAT0BAQL/AUcBAQL/AUcB
AQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQH/AkcBRgGA/wCBAAH/AUcBAQL/AUcBAQL/AUcB
AQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUcBAQL/AUgBAQH/Af4BSgEAAv8BjQE2Av8B
0QFsAf8B+wHHAUcB/wH3Ab4BIgH/AfsBuQESAv8BtQECAf8B/QG1AQgB/wH8AbYBDQH/AfsBrwENAf8B
+wGoAQ0B/wHoAXIBCAH/AdUBPAEDAf8B6gFCAQIC/wFIAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC
/wFHAQEC/wFHAQEB/wJHAUYBgP8AgQAB/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC
/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFGAQAC/wGPAVMC/wHYAaYB/wH4Ac4BdQH/AfEBxAFEAf8B
+AG8ASQC/wG0AQMB/wH8AbYBDgH/AfgBtwEZAf8B+AGrARkB/wH3AZ4BGAH/AfsBcgEPAv8BRQEGAv8B
RwEDAv8BSAEAAv8BSAEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAf8CRwFGAYD/AIEAAf8B
RwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BSAEBAf8B/QFIAQAB
/wH7AUgBAAH/Af0BbgEsAv8BlAFZAf8B/AGOAT8B/wH4AYgBJQH/Ae8BhAEUAf8B5gGBAQMB/wHtAYEB
CAH/AfUBgQEOAf8B+AF5AQ8B/wH7AXIBEAH/Af0BXQEJAv8BRwEDAv8BRwECAv8BSAEBAv8BRwEBAv8B
RwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAf8CRwFGAYD/AIEAAf8BRwEBAv8BRwEBAv8BRwEBAv8B
RwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BSAEBAf8B/gFIAQAB/wH6AUkBAAH/AfYBSQEAAf8B+wFNAQYC
/wFQAQsC/wFOAQkC/wFMAQYB/wHmAU0BBAH/AcwBTQECAf8B3wFMAQMB/wHyAUoBAwH/AfkBSAEFAv8B
RgEHAv8BSAEEAf8B/gFJAQAC/wFIAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC
/wFHAQEB/wJHAUYBgP8AgQAB/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC/wFHAQEC
/wFHAQEC/wFIAQEB/wH9AUgBAQH/AfsBSAEBAf8B/QFKAQMC/wFMAQYC/wFLAQUC/wFKAQQB/wHyAUoB
AwH/AeYBSgECAf8B7wFJAQIB/wH5AUkBAgH/AfwBSAEDAv8BRwEEAv8BRwECAv8BSAEBAv8BSAEBAv8B
RwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAf8CRwFGAYD/AIEAAf8BRwEBAv8B
RwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8B
RwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8B
RwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAf8C
RwFGAYD/AIEAAf8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8B
RwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8B
RwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8B
RwEBAv8BRwEBAv8BRwEBAf8CRwFGAYD/AIEAAf8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8B
RwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8B
RwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8B
RwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAv8BRwEBAf8CRwFGAYD/AIEAAUIBTQE+BwABPgMAASgD
AAGAAwABIAMAAQEBAAEBBgABAhYAA///AP8AAwAL
</value>
</data>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />

View File

@ -29,23 +29,14 @@
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DirectMessage));
rtxtChat = new RichTextBox();
btnSend = new Button();
rtxtChatbox = new RichTextBox();
lblUsername = new Label();
pbPfp = new PictureBox();
fpnlMessages = new FlowLayoutPanel();
((System.ComponentModel.ISupportInitialize)pbPfp).BeginInit();
SuspendLayout();
//
// rtxtChat
//
rtxtChat.HideSelection = false;
rtxtChat.Location = new Point(12, 48);
rtxtChat.Margin = new Padding(4, 3, 4, 3);
rtxtChat.Name = "rtxtChat";
rtxtChat.ReadOnly = true;
rtxtChat.Size = new Size(593, 325);
rtxtChat.TabIndex = 6;
rtxtChat.Text = "";
//
// btnSend
//
btnSend.FlatAppearance.BorderSize = 0;
@ -74,21 +65,44 @@
//
lblUsername.AutoSize = true;
lblUsername.Font = new Font("Segoe UI", 25F, FontStyle.Bold | FontStyle.Italic);
lblUsername.Location = new Point(6, 0);
lblUsername.Location = new Point(52, 0);
lblUsername.Margin = new Padding(4, 0, 4, 0);
lblUsername.Name = "lblUsername";
lblUsername.Size = new Size(181, 46);
lblUsername.TabIndex = 7;
lblUsername.Text = "Username";
//
// pbPfp
//
pbPfp.Image = Properties.Resources.DefaultPfp;
pbPfp.Location = new Point(14, 6);
pbPfp.Name = "pbPfp";
pbPfp.Size = new Size(40, 37);
pbPfp.SizeMode = PictureBoxSizeMode.StretchImage;
pbPfp.TabIndex = 9;
pbPfp.TabStop = false;
//
// fpnlMessages
//
fpnlMessages.AutoScroll = true;
fpnlMessages.BackColor = Color.White;
fpnlMessages.BorderStyle = BorderStyle.Fixed3D;
fpnlMessages.FlowDirection = FlowDirection.TopDown;
fpnlMessages.Location = new Point(14, 49);
fpnlMessages.Name = "fpnlMessages";
fpnlMessages.Size = new Size(591, 324);
fpnlMessages.TabIndex = 11;
fpnlMessages.WrapContents = false;
//
// DirectMessage
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
BackColor = Color.DodgerBlue;
ClientSize = new Size(618, 443);
Controls.Add(fpnlMessages);
Controls.Add(pbPfp);
Controls.Add(lblUsername);
Controls.Add(rtxtChat);
Controls.Add(btnSend);
Controls.Add(rtxtChatbox);
Font = new Font("Segoe UI", 9F);
@ -101,15 +115,16 @@
StartPosition = FormStartPosition.CenterScreen;
Text = "QtC.NET Client - Direct Message With ${USER}";
Load += frmDirectMessage_Load;
((System.ComponentModel.ISupportInitialize)pbPfp).EndInit();
ResumeLayout(false);
PerformLayout();
}
#endregion
private RichTextBox rtxtChat;
private Button btnSend;
private RichTextBox rtxtChatbox;
private Label lblUsername;
private PictureBox pbPfp;
private FlowLayoutPanel fpnlMessages;
}
}

View File

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc.ModelBinding;
using qtc_net_client_2.Controls;
using qtc_net_client_2.Services;
using QtCNETAPI.Dtos.User;
using QtCNETAPI.Events;
@ -36,20 +37,23 @@ namespace qtc_net_client_2.Forms
InitializeComponent();
}
private void frmDirectMessage_Load(object sender, EventArgs e)
private async void frmDirectMessage_Load(object sender, EventArgs e)
{
lblUsername.Text = User.Username;
Text = $"QtC.NET Client - Direct Message With {User.Username}";
Messages.CollectionChanged += Messages_CollectionChanged;
if (User.Role == "Admin")
var pfpRes = await _apiService.GetUserProfilePic(User.Id);
if(pfpRes != null && pfpRes.Success && pfpRes.Data != null)
{
Messages.Add($"[SERVER] This User Is A Server Admin. You should comply with anything this user asks. however admins should not ask for personal information.\n");
using var ms = new MemoryStream(pfpRes.Data);
using var img = Image.FromStream(ms);
pbPfp.Image = new Bitmap(img);
}
if (InitMessage != null)
{
Messages.Add($"[{User.Username}] {InitMessage.Content}\n");
Messages.Add($"{User.Username}: {InitMessage.Content}");
AudioService.PlaySoundEffect("sndDirectMsg");
}
}
@ -63,7 +67,7 @@ namespace qtc_net_client_2.Forms
if (!string.IsNullOrEmpty(rtxtChatbox.Text))
{
await _gatewayService.SendDirectMessageAsync(User, new QtCNETAPI.Models.Message { Content = rtxtChatbox.Text, AuthorId = _apiService.CurrentUser.Id });
Messages.Add($"[{_apiService.CurrentUser.Username}] {rtxtChatbox.Text}\n");
Messages.Add($"{_apiService.CurrentUser.Username}: {rtxtChatbox.Text}");
rtxtChatbox.Clear();
AudioService.PlaySoundEffect("sndSendClick");
}
@ -74,7 +78,7 @@ namespace qtc_net_client_2.Forms
if (!string.IsNullOrEmpty(rtxtChatbox.Text))
{
await _gatewayService.SendDirectMessageAsync(User, new QtCNETAPI.Models.Message { Content = rtxtChatbox.Text, AuthorId = _apiService.CurrentUser.Id });
Messages.Add($"[{_apiService.CurrentUser.Username}] {rtxtChatbox.Text}\n");
Messages.Add($"{_apiService.CurrentUser.Username}: {rtxtChatbox.Text}");
rtxtChatbox.Clear();
AudioService.PlaySoundEffect("sndSendClick");
}
@ -97,14 +101,36 @@ namespace qtc_net_client_2.Forms
Invoke(delegate ()
{
var msg = e.NewItems.Cast<string>().FirstOrDefault();
rtxtChat.AppendText(msg);
var ctrl = new ChatMessageControlMinimal()
{
Username = msg!.Split(':')[0],
Message = msg!.Split(":")[1].Trim(),
};
ctrl.Height = ctrl.CalculateHeight(ctrl.Width);
fpnlMessages.Controls.Add(ctrl);
fpnlMessages.VerticalScroll.Value = fpnlMessages.VerticalScroll.Maximum;
fpnlMessages.PerformLayout();
if (!msg!.Contains(_apiService.CurrentUser.Username)) AudioService.PlaySoundEffect("sndMessage");
});
}
else
{
var msg = e.NewItems.Cast<string>().FirstOrDefault();
rtxtChat.AppendText(msg);
var ctrl = new ChatMessageControlMinimal()
{
Username = msg!.Split(':')[0],
Message = msg!.Split(":")[1].Trim(),
};
ctrl.Height = ctrl.CalculateHeight(ctrl.Width);
fpnlMessages.Controls.Add(ctrl);
fpnlMessages.VerticalScroll.Value = fpnlMessages.VerticalScroll.Maximum;
fpnlMessages.PerformLayout();
if (!msg!.Contains(_apiService.CurrentUser.Username)) AudioService.PlaySoundEffect("sndMessage");
}
}

View File

@ -32,11 +32,13 @@
pbLoginBanner = new PictureBox();
tbEmail = new TextBox();
lblEmail = new Label();
label1 = new Label();
lblPassword = new Label();
tbPassword = new TextBox();
btnLogin = new Button();
llblRegister = new LinkLabel();
cbRememberMe = new CheckBox();
llblResendEmail = new LinkLabel();
llblForgotPasswor = new LinkLabel();
((System.ComponentModel.ISupportInitialize)pbLoginBanner).BeginInit();
SuspendLayout();
//
@ -68,16 +70,16 @@
lblEmail.TabIndex = 2;
lblEmail.Text = "Email";
//
// label1
// lblPassword
//
label1.AutoSize = true;
label1.Font = new Font("Segoe UI Light", 9F);
label1.ForeColor = SystemColors.ControlLight;
label1.Location = new Point(11, 138);
label1.Name = "label1";
label1.Size = new Size(55, 15);
label1.TabIndex = 4;
label1.Text = "Password";
lblPassword.AutoSize = true;
lblPassword.Font = new Font("Segoe UI Light", 9F);
lblPassword.ForeColor = SystemColors.ControlLight;
lblPassword.Location = new Point(11, 138);
lblPassword.Name = "lblPassword";
lblPassword.Size = new Size(55, 15);
lblPassword.TabIndex = 4;
lblPassword.Text = "Password";
//
// tbPassword
//
@ -117,21 +119,49 @@
cbRememberMe.ForeColor = SystemColors.ControlLight;
cbRememberMe.Location = new Point(198, 168);
cbRememberMe.Name = "cbRememberMe";
cbRememberMe.Size = new Size(157, 19);
cbRememberMe.Size = new Size(163, 19);
cbRememberMe.TabIndex = 7;
cbRememberMe.Text = "Remember Me For 7 Days";
cbRememberMe.Text = "Remember Me For 30 Days";
cbRememberMe.UseVisualStyleBackColor = true;
//
// frmLogin
// llblResendEmail
//
llblResendEmail.AutoSize = true;
llblResendEmail.Font = new Font("Segoe UI Light", 9F);
llblResendEmail.LinkColor = SystemColors.ControlLight;
llblResendEmail.Location = new Point(369, 164);
llblResendEmail.Name = "llblResendEmail";
llblResendEmail.Size = new Size(129, 15);
llblResendEmail.TabIndex = 8;
llblResendEmail.TabStop = true;
llblResendEmail.Text = "Resend Verification Email";
llblResendEmail.LinkClicked += llblResendEmail_LinkClicked;
//
// llblForgotPasswor
//
llblForgotPasswor.AutoSize = true;
llblForgotPasswor.Font = new Font("Segoe UI Light", 9F);
llblForgotPasswor.LinkColor = SystemColors.ControlLight;
llblForgotPasswor.Location = new Point(401, 181);
llblForgotPasswor.Name = "llblForgotPasswor";
llblForgotPasswor.Size = new Size(98, 15);
llblForgotPasswor.TabIndex = 9;
llblForgotPasswor.TabStop = true;
llblForgotPasswor.Text = "Forgot Password?";
llblForgotPasswor.LinkClicked += llblForgotPasswor_LinkClicked;
//
// Login
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
BackColor = Color.DodgerBlue;
ClientSize = new Size(515, 203);
Controls.Add(llblForgotPasswor);
Controls.Add(llblResendEmail);
Controls.Add(cbRememberMe);
Controls.Add(llblRegister);
Controls.Add(btnLogin);
Controls.Add(label1);
Controls.Add(lblPassword);
Controls.Add(tbPassword);
Controls.Add(lblEmail);
Controls.Add(tbEmail);
@ -139,7 +169,7 @@
FormBorderStyle = FormBorderStyle.FixedDialog;
Icon = (Icon)resources.GetObject("$this.Icon");
MaximizeBox = false;
Name = "frmLogin";
Name = "Login";
StartPosition = FormStartPosition.CenterParent;
Text = "QtC.NET Client - Login";
Load += frmLogin_Load;
@ -153,10 +183,12 @@
private PictureBox pbLoginBanner;
private TextBox tbEmail;
private Label lblEmail;
private Label label1;
private Label lblPassword;
private TextBox tbPassword;
private Button btnLogin;
private LinkLabel llblRegister;
private CheckBox cbRememberMe;
private LinkLabel llblResendEmail;
private LinkLabel llblForgotPasswor;
}
}

View File

@ -1,4 +1,5 @@
using QtCNETAPI.Services.ApiService;
using QtCNETAPI.Services;
using QtCNETAPI.Dtos.User;
using System;
using System.Collections.Generic;
@ -9,12 +10,14 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using qtc_net_client_2.Services;
namespace qtc_net_client_2.Forms
{
public partial class Login : Form
{
private IApiService _apiService;
private CredentialService _credService = new();
public Login(IApiService apiService)
{
_apiService = apiService;
@ -24,14 +27,14 @@ namespace qtc_net_client_2.Forms
private async void frmLogin_Load(object sender, EventArgs e)
{
if (File.Exists("./session.token"))
string? accessToken = _credService.GetAccessToken();
if (accessToken != null)
{
ToggleControls(false, false);
// try logging in with the token in the file
string token = File.ReadAllText("./session.token");
var result = await _apiService.RefreshLogin(token);
// try logging in with the token in cred storage
var result = await _apiService.RefreshLogin(accessToken);
if (result.Success)
{
DialogResult = DialogResult.OK;
@ -55,8 +58,9 @@ namespace qtc_net_client_2.Forms
RememberMe = cbRememberMe.Checked
});
if (result.Success)
if (result.Success && result.Data != null)
{
_credService.SaveAccessToken(_apiService.CurrentUser.Username, result.Data);
DialogResult = DialogResult.OK;
Close();
}
@ -68,6 +72,24 @@ namespace qtc_net_client_2.Forms
}
}
private void llblRegister_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
Register frmRegister = new Register(_apiService);
frmRegister.ShowDialog();
}
private void llblResendEmail_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
ResendVerificationEmail resendVerificationEmail = new ResendVerificationEmail(_apiService);
resendVerificationEmail.ShowDialog();
}
private void llblForgotPasswor_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
ResetPassword resetPassword = new ResetPassword(_apiService);
resetPassword.ShowDialog();
}
private void ToggleControls(bool enable, bool clearText)
{
tbEmail.Enabled = enable;
@ -81,11 +103,5 @@ namespace qtc_net_client_2.Forms
tbPassword.Text = string.Empty;
}
}
private void llblRegister_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
Register frmRegister = new Register(_apiService);
frmRegister.ShowDialog();
}
}
}

View File

@ -30,17 +30,16 @@
{
components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Main));
ListViewItem listViewItem1 = new ListViewItem("Stock Market", 0);
ListViewItem listViewItem2 = new ListViewItem("Guess The Number", 1);
ListViewItem listViewItem3 = new ListViewItem("Tic-Tac-Toe (Multiplayer)", "Tic-tac-toe.png");
ListViewItem listViewItem4 = new ListViewItem("Stock Market", 0);
ListViewItem listViewItem5 = new ListViewItem("Guess The Number", 1);
ListViewItem listViewItem6 = new ListViewItem("Tic-Tac-Toe (Multiplayer)", "Tic-tac-toe.png");
tbcMain = new TabControl();
tbpContacts = new TabPage();
lvContacts = new ListView();
flpContacts = new FlowLayoutPanel();
ctxmRefresh = new ContextMenuStrip(components);
refreshToolStripMenuItem = new ToolStripMenuItem();
ilProfilePics = new ImageList(components);
tbpRooms = new TabPage();
lbRooms = new ListBox();
flpRooms = new FlowLayoutPanel();
tbpUsers = new TabPage();
lvUserDirectory = new ListView();
ilStatusIcons = new ImageList(components);
@ -51,6 +50,7 @@
lvStoreItems = new ListView();
ilStoreThumbnails = new ImageList(components);
ilTabIcons = new ImageList(components);
ilProfilePics = new ImageList(components);
ctxmChangeStatus = new ContextMenuStrip(components);
onlineToolStripMenuItem = new ToolStripMenuItem();
awayToolStripMenuItem = new ToolStripMenuItem();
@ -117,7 +117,7 @@
//
// tbpContacts
//
tbpContacts.Controls.Add(lvContacts);
tbpContacts.Controls.Add(flpContacts);
tbpContacts.ImageKey = "ContactsIcon.png";
tbpContacts.Location = new Point(4, 24);
tbpContacts.Name = "tbpContacts";
@ -127,21 +127,19 @@
tbpContacts.Text = "Contacts";
tbpContacts.UseVisualStyleBackColor = true;
//
// lvContacts
// flpContacts
//
lvContacts.Alignment = ListViewAlignment.Left;
lvContacts.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
lvContacts.ContextMenuStrip = ctxmRefresh;
lvContacts.LargeImageList = ilProfilePics;
lvContacts.Location = new Point(0, 0);
lvContacts.MultiSelect = false;
lvContacts.Name = "lvContacts";
lvContacts.Size = new Size(344, 478);
lvContacts.SmallImageList = ilProfilePics;
lvContacts.TabIndex = 1;
lvContacts.UseCompatibleStateImageBehavior = false;
lvContacts.View = View.SmallIcon;
lvContacts.DoubleClick += lvContacts_DoubleClick;
flpContacts.AutoScroll = true;
flpContacts.BackColor = Color.White;
flpContacts.BorderStyle = BorderStyle.Fixed3D;
flpContacts.ContextMenuStrip = ctxmRefresh;
flpContacts.Dock = DockStyle.Fill;
flpContacts.FlowDirection = FlowDirection.TopDown;
flpContacts.Location = new Point(3, 3);
flpContacts.Name = "flpContacts";
flpContacts.Size = new Size(338, 465);
flpContacts.TabIndex = 0;
flpContacts.WrapContents = false;
//
// ctxmRefresh
//
@ -156,16 +154,9 @@
refreshToolStripMenuItem.Text = "Refresh";
refreshToolStripMenuItem.Click += refreshToolStripMenuItem_Click;
//
// ilProfilePics
//
ilProfilePics.ColorDepth = ColorDepth.Depth32Bit;
ilProfilePics.ImageStream = (ImageListStreamer)resources.GetObject("ilProfilePics.ImageStream");
ilProfilePics.TransparentColor = Color.Transparent;
ilProfilePics.Images.SetKeyName(0, "DEFAULT");
//
// tbpRooms
//
tbpRooms.Controls.Add(lbRooms);
tbpRooms.Controls.Add(flpRooms);
tbpRooms.ImageKey = "RoomsChatIcon.png";
tbpRooms.Location = new Point(4, 24);
tbpRooms.Name = "tbpRooms";
@ -175,17 +166,19 @@
tbpRooms.Text = "Rooms";
tbpRooms.UseVisualStyleBackColor = true;
//
// lbRooms
// flpRooms
//
lbRooms.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
lbRooms.ContextMenuStrip = ctxmRefresh;
lbRooms.FormattingEnabled = true;
lbRooms.ItemHeight = 15;
lbRooms.Location = new Point(0, 0);
lbRooms.Name = "lbRooms";
lbRooms.Size = new Size(344, 484);
lbRooms.TabIndex = 0;
lbRooms.DoubleClick += lbRooms_DoubleClick;
flpRooms.AutoScroll = true;
flpRooms.BackColor = Color.White;
flpRooms.BorderStyle = BorderStyle.Fixed3D;
flpRooms.ContextMenuStrip = ctxmRefresh;
flpRooms.Dock = DockStyle.Fill;
flpRooms.FlowDirection = FlowDirection.TopDown;
flpRooms.Location = new Point(3, 3);
flpRooms.Name = "flpRooms";
flpRooms.Size = new Size(338, 465);
flpRooms.TabIndex = 1;
flpRooms.WrapContents = false;
//
// tbpUsers
//
@ -238,10 +231,10 @@
// lvGames
//
lvGames.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
listViewItem1.Tag = "StockMarketGame";
listViewItem2.Tag = "GuessTheNumberGame";
listViewItem3.Tag = "TicTacToeGame";
lvGames.Items.AddRange(new ListViewItem[] { listViewItem1, listViewItem2, listViewItem3 });
listViewItem4.Tag = "StockMarketGame";
listViewItem5.Tag = "GuessTheNumberGame";
listViewItem6.Tag = "TicTacToeGame";
lvGames.Items.AddRange(new ListViewItem[] { listViewItem4, listViewItem5, listViewItem6 });
lvGames.LargeImageList = ilGames;
lvGames.Location = new Point(0, 0);
lvGames.MultiSelect = false;
@ -277,6 +270,7 @@
//
lvStoreItems.LargeImageList = ilStoreThumbnails;
lvStoreItems.Location = new Point(0, 0);
lvStoreItems.MultiSelect = false;
lvStoreItems.Name = "lvStoreItems";
lvStoreItems.Size = new Size(344, 484);
lvStoreItems.SmallImageList = ilStoreThumbnails;
@ -300,6 +294,13 @@
ilTabIcons.Images.SetKeyName(2, "RoomsChatIcon.png");
ilTabIcons.Images.SetKeyName(3, "CurrencyIcon.png");
//
// ilProfilePics
//
ilProfilePics.ColorDepth = ColorDepth.Depth32Bit;
ilProfilePics.ImageStream = (ImageListStreamer)resources.GetObject("ilProfilePics.ImageStream");
ilProfilePics.TransparentColor = Color.Transparent;
ilProfilePics.Images.SetKeyName(0, "DEFAULT");
//
// ctxmChangeStatus
//
ctxmChangeStatus.Items.AddRange(new ToolStripItem[] { onlineToolStripMenuItem, awayToolStripMenuItem, doNotDisturbToolStripMenuItem, invisibleToolStripMenuItem });
@ -469,7 +470,6 @@
//
// pbUserPfp
//
pbUserPfp.BorderStyle = BorderStyle.FixedSingle;
pbUserPfp.ContextMenuStrip = ctxmChangeStatus;
pbUserPfp.Cursor = Cursors.Hand;
pbUserPfp.Image = Properties.Resources.DefaultPfp;
@ -498,39 +498,39 @@
//
ctxmAdminUserList.Items.AddRange(new ToolStripItem[] { refreshToolStripMenuItem1, toolStripSeparator1, copyUserIDToClipboardToolStripMenuItem, deleteUserToolStripMenuItem, adminDirectMessageToolStripMenuItem });
ctxmAdminUserList.Name = "contextMenuStrip1";
ctxmAdminUserList.Size = new Size(213, 98);
ctxmAdminUserList.Size = new Size(214, 98);
ctxmAdminUserList.Opening += ctxmAdminUserList_Opening;
//
// refreshToolStripMenuItem1
//
refreshToolStripMenuItem1.Name = "refreshToolStripMenuItem1";
refreshToolStripMenuItem1.Size = new Size(212, 22);
refreshToolStripMenuItem1.Size = new Size(213, 22);
refreshToolStripMenuItem1.Text = "Refresh";
refreshToolStripMenuItem1.Click += refreshToolStripMenuItem_Click;
//
// toolStripSeparator1
//
toolStripSeparator1.Name = "toolStripSeparator1";
toolStripSeparator1.Size = new Size(209, 6);
toolStripSeparator1.Size = new Size(210, 6);
//
// copyUserIDToClipboardToolStripMenuItem
//
copyUserIDToClipboardToolStripMenuItem.Name = "copyUserIDToClipboardToolStripMenuItem";
copyUserIDToClipboardToolStripMenuItem.Size = new Size(212, 22);
copyUserIDToClipboardToolStripMenuItem.Size = new Size(213, 22);
copyUserIDToClipboardToolStripMenuItem.Text = "Copy User ID To Clipboard";
copyUserIDToClipboardToolStripMenuItem.Click += copyUserIDToClipboardToolStripMenuItem_Click;
//
// deleteUserToolStripMenuItem
//
deleteUserToolStripMenuItem.Name = "deleteUserToolStripMenuItem";
deleteUserToolStripMenuItem.Size = new Size(212, 22);
deleteUserToolStripMenuItem.Size = new Size(213, 22);
deleteUserToolStripMenuItem.Text = "Delete User";
deleteUserToolStripMenuItem.Click += deleteUserToolStripMenuItem_Click;
//
// adminDirectMessageToolStripMenuItem
//
adminDirectMessageToolStripMenuItem.Name = "adminDirectMessageToolStripMenuItem";
adminDirectMessageToolStripMenuItem.Size = new Size(212, 22);
adminDirectMessageToolStripMenuItem.Size = new Size(213, 22);
adminDirectMessageToolStripMenuItem.Text = "Admin Direct Message";
adminDirectMessageToolStripMenuItem.Click += adminDirectMessageToolStripMenuItem_Click;
//
@ -539,7 +539,6 @@
ctxmAdminRoomList.Items.AddRange(new ToolStripItem[] { toolStripMenuItem1, toolStripSeparator2, addRoomToolStripMenuItem, deleteRoomToolStripMenuItem });
ctxmAdminRoomList.Name = "contextMenuStrip1";
ctxmAdminRoomList.Size = new Size(143, 76);
ctxmAdminRoomList.Opening += ctxmAdminRoomList_Opening;
//
// toolStripMenuItem1
//
@ -565,7 +564,6 @@
deleteRoomToolStripMenuItem.Name = "deleteRoomToolStripMenuItem";
deleteRoomToolStripMenuItem.Size = new Size(142, 22);
deleteRoomToolStripMenuItem.Text = "Delete Room";
deleteRoomToolStripMenuItem.Click += deleteRoomToolStripMenuItem_Click;
//
// lblConnectionLost
//
@ -626,9 +624,7 @@
private TabControl tbcMain;
private TabPage tbpContacts;
private TabPage tbpRooms;
private ListBox lbRooms;
private Label lblRequestNotif;
private ListView lvContacts;
private System.Windows.Forms.ImageList ilProfilePics;
private NotifyIcon niMain;
private ImageList ilTabIcons;
@ -654,7 +650,6 @@
private ToolStripMenuItem refreshToolStripMenuItem;
private ImageList ilStatusIcons;
private TabPage tbpUsers;
private ListView lvUserDirectory;
private PictureBox pbDonate;
private TabPage tbpStore;
private ListView lvStoreItems;
@ -671,5 +666,8 @@
private ToolStripMenuItem addRoomToolStripMenuItem;
private ToolStripMenuItem deleteRoomToolStripMenuItem;
private Label lblConnectionLost;
private FlowLayoutPanel flpContacts;
private ListView lvUserDirectory;
private FlowLayoutPanel flpRooms;
}
}

View File

@ -1,14 +1,16 @@
using QtCNETAPI.Dtos.User;
using QtCNETAPI.Services.ApiService;
using QtCNETAPI.Services.GatewayService;
using QtCNETAPI.Events;
using QtCNETAPI.Models;
using Microsoft.VisualBasic.ApplicationServices;
using qtc_net_client_2.ClientModel;
using qtc_net_client_2.Controls;
using qtc_net_client_2.Forms;
using qtc_net_client_2.Services;
using qtc_net_client_2.ClientModel;
using System.Threading.Tasks;
using QtCNETAPI.Dtos.User;
using QtCNETAPI.Events;
using QtCNETAPI.Models;
using QtCNETAPI.Schema;
using QtCNETAPI.Services;
using QtCNETAPI.Services.ApiService;
using QtCNETAPI.Services.GatewayService;
using System.Threading.Tasks;
namespace qtc_net_client_2
{
@ -20,6 +22,8 @@ namespace qtc_net_client_2
private Config _config;
private ServerConfig _serverConfig;
private AudioService AudioService = new();
private ImageFactory _imgFactory = new();
private CredentialService _credService = new();
private LoggingService LoggingService;
public List<Room> RoomList = [];
@ -39,6 +43,8 @@ namespace qtc_net_client_2
private async void frmMain_Load(object sender, EventArgs e)
{
flpContacts.Padding = new Padding(8);
LoggingService.LogString("Main Form Loaded");
// start request notif blink task
@ -67,36 +73,30 @@ namespace qtc_net_client_2
await OnSuccessfulLogin();
}
private async void lbRooms_DoubleClick(object sender, EventArgs e)
private async void OnRoomDoubleClicked(object? sender, EventArgs e)
{
if (lbRooms.SelectedItems.Count > 0)
RoomEntryControl? ctrl = sender as RoomEntryControl;
string? selectedRoom = ctrl?.RoomName;
if (selectedRoom != null)
{
string? selectedRoom = (string?)lbRooms.SelectedItems[lbRooms.SelectedItems.Count - 1];
if (selectedRoom != null)
if (selectedRoom == "Lobby")
{
if (selectedRoom == "Lobby")
{
// join lobby
if (!_gatewayService.InLobby) await _gatewayService.JoinLobbyAsync();
ChatRoom frmChat = new ChatRoom(_gatewayService, _apiService);
frmChat.Show();
ChatRoom frmChat = new ChatRoom(_gatewayService, _apiService);
frmChat.Show();
LoggingService.LogString("User Has Joined Lobby Room");
return;
}
LoggingService.LogString("User Has Joined Lobby Room");
return;
}
// join the room
Room? room = RoomList.FirstOrDefault(e => e.Name == selectedRoom);
if (room != null)
{
ChatRoom frmChat = new ChatRoom(_gatewayService, _apiService, room);
frmChat.Show();
// join the room
Room? room = RoomList.FirstOrDefault(e => e.Name == selectedRoom);
if (room != null)
{
if (_gatewayService.CurrentRoom != room) await _gatewayService.JoinRoomAsync(room);
ChatRoom frmChat = new ChatRoom(_gatewayService, _apiService);
frmChat.Show();
LoggingService.LogString($"User Has Joined {room.Name}");
}
LoggingService.LogString($"User Has Joined {room.Name}");
}
}
}
@ -123,15 +123,30 @@ namespace qtc_net_client_2
{
// update profile pic in ui
var pfpRes = await _apiService.GetUserProfilePic(_apiService.CurrentUser.Id);
var cosmeticRes = await GetCosmeticImage(_apiService.CurrentUser.ActiveProfileCosmetic);
// TODO - refactor this a bit
if (pfpRes.Success && pfpRes.Data != null)
{
using (var ms = new MemoryStream(pfpRes.Data))
using var pfpMS = new MemoryStream(pfpRes.Data);
var pfp = (Bitmap)Image.FromStream(pfpMS);
if (cosmeticRes != null)
{
pbUserPfp.Image = Image.FromStream(ms);
ms.Dispose();
using var cosmeticMS = new MemoryStream(cosmeticRes);
var cosmetic = (Bitmap)Image.FromStream(cosmeticMS);
pbUserPfp.Image = _imgFactory.CreateProfileImage(null, pfp, cosmetic);
}
else pbUserPfp.Image = _imgFactory.CreateProfileImage(null, pfp, null);
}
else if (cosmeticRes != null)
{
using var cosmeticMS = new MemoryStream(cosmeticRes);
var cosmetic = (Bitmap)Image.FromStream(cosmeticMS);
pbUserPfp.Image = _imgFactory.CreateProfileImage(null, null, cosmetic);
}
else LoggingService.LogString($"User Has No Profile Picture Or It Could Not Be Loaded.\n{pfpRes.Message}");
}
}
}
@ -145,41 +160,42 @@ namespace qtc_net_client_2
{
if (MessageBox.Show("Are You Sure You Want To Sign Out?\nThis Deletes Your session.token, Requiring You To Sign In Again", "are you sure...?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
{
File.Delete("./session.token");
_credService.DeleteAccessToken();
Environment.Exit(0);
}
}
private void llblEditProfile_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
private async void llblEditProfile_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
ProfileEdit frmProfileEdit = new ProfileEdit(_apiService);
frmProfileEdit.ShowDialog();
}
private async void lvContacts_DoubleClick(object sender, EventArgs e)
{
if (lvContacts.SelectedItems.Count > 0)
var result = frmProfileEdit.ShowDialog();
if (result == DialogResult.Yes)
{
string? selectedUser = (string?)lvContacts.SelectedItems[lvContacts.SelectedItems.Count - 1].Text;
// update profile pic in ui
var pfpRes = await _apiService.GetUserProfilePic(_apiService.CurrentUser.Id);
var cosmeticRes = await GetCosmeticImage(_apiService.CurrentUser.ActiveProfileCosmetic);
if (selectedUser != null)
// TODO - refactor this a bit
if (pfpRes.Success && pfpRes.Data != null)
{
// split from [ if it exists
if (selectedUser.Contains('[')) selectedUser = selectedUser.Split('[', options: StringSplitOptions.TrimEntries)[0];
using var pfpMS = new MemoryStream(pfpRes.Data);
var pfp = (Bitmap)Image.FromStream(pfpMS);
// get user info and open profile dialog
var user = UserDirectory.FirstOrDefault(e => e.Username == selectedUser);
var res = await _apiService.GetUserInformationAsync(user!.Id);
var pfpRes = await _apiService.GetUserProfilePic(user!.Id);
if (pfpRes != null && !pfpRes.Success) LoggingService.LogString($"User Has No Profile Picture Or It Could Not Be Loaded.\n{pfpRes.Message}");
if (res.Data != null && res.Success)
if (cosmeticRes != null)
{
LoggingService.LogString($"Opening Profile For User '{res.Data.Username}'");
Profile frmProfile = new Profile(res.Data, pfpRes, Contacts, _apiService, _gatewayService);
frmProfile.Show();
using var cosmeticMS = new MemoryStream(cosmeticRes);
var cosmetic = (Bitmap)Image.FromStream(cosmeticMS);
pbUserPfp.Image = _imgFactory.CreateProfileImage(null, pfp, cosmetic);
}
else pbUserPfp.Image = _imgFactory.CreateProfileImage(null, pfp, null);
}
else if (cosmeticRes != null)
{
using var cosmeticMS = new MemoryStream(cosmeticRes);
var cosmetic = (Bitmap)Image.FromStream(cosmeticMS);
pbUserPfp.Image = _imgFactory.CreateProfileImage(null, null, cosmetic);
}
}
}
@ -296,12 +312,16 @@ namespace qtc_net_client_2
var res = await _apiService.GetUserInformationAsync(user!.Id);
var pfpRes = await _apiService.GetUserProfilePic(user!.Id);
// get cosmetic
byte[]? cosmeticData = null;
if (user.ProfileCosmeticId != 0) cosmeticData = await GetCosmeticImage(user.ProfileCosmeticId);
if (pfpRes != null && !pfpRes.Success) LoggingService.LogString($"User Has No Profile Picture Or It Could Not Be Loaded.\n{pfpRes.Message}");
if (res.Data != null && res.Success)
{
LoggingService.LogString($"Opening Profile For User '{res.Data.Username}'");
Profile frmProfile = new Profile(res.Data, pfpRes, Contacts, _apiService, _gatewayService);
Profile frmProfile = new Profile(res.Data, pfpRes, Contacts, _apiService, _gatewayService, cosmeticData);
frmProfile.Show();
}
}
@ -378,7 +398,36 @@ namespace qtc_net_client_2
if (item != null && item.Success && item.Data != null)
{
StoreItemDisplay storeItemDisplay = new StoreItemDisplay(item.Data, LoggingService, _apiService);
storeItemDisplay.ShowDialog();
var result = storeItemDisplay.ShowDialog();
if (result == DialogResult.Yes)
{
// update pfp in ui
var pfpRes = await _apiService.GetUserProfilePic(_apiService.CurrentUser.Id);
var cosmeticRes = await GetCosmeticImage(_apiService.CurrentUser.ActiveProfileCosmetic);
// TODO - refactor this a bit
if (pfpRes.Success && pfpRes.Data != null)
{
using var pfpMS = new MemoryStream(pfpRes.Data);
var pfp = (Bitmap)Image.FromStream(pfpMS);
if (cosmeticRes != null)
{
using var cosmeticMS = new MemoryStream(cosmeticRes);
var cosmetic = (Bitmap)Image.FromStream(cosmeticMS);
pbUserPfp.Image = _imgFactory.CreateProfileImage(null, pfp, cosmetic);
}
else pbUserPfp.Image = _imgFactory.CreateProfileImage(null, pfp, null);
}
else if (cosmeticRes != null)
{
using var cosmeticMS = new MemoryStream(cosmeticRes);
var cosmetic = (Bitmap)Image.FromStream(cosmeticMS);
pbUserPfp.Image = _imgFactory.CreateProfileImage(null, null, cosmetic);
}
}
}
}
}
@ -390,12 +439,13 @@ namespace qtc_net_client_2
createRoom.ShowDialog();
}
private void ctxmAdminRoomList_Opening(object sender, System.ComponentModel.CancelEventArgs e)
{
if (lbRooms.SelectedItem == null)
deleteRoomToolStripMenuItem.Enabled = false;
else deleteRoomToolStripMenuItem.Enabled = true;
}
// TODO - redo this
//private void ctxmAdminRoomList_Opening(object sender, System.ComponentModel.CancelEventArgs e)
//{
// if (lbRooms.SelectedItem == null)
// deleteRoomToolStripMenuItem.Enabled = false;
// else deleteRoomToolStripMenuItem.Enabled = true;
//}
private void ctxmAdminUserList_Opening(object sender, System.ComponentModel.CancelEventArgs e)
{
@ -445,35 +495,36 @@ namespace qtc_net_client_2
}
}
private async void deleteRoomToolStripMenuItem_Click(object sender, EventArgs e)
{
if (lbRooms.SelectedItems.Count > 0)
{
string? itemSelected = (string?)lbRooms.SelectedItems[lbRooms.SelectedItems.Count - 1];
if (itemSelected != null)
{
var dialogResult = MessageBox.Show("Are You Sure You Want To Delete This Room?\nThis will kick everyone currently in the room out.",
"are you sure..?",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
// TODO - i have no idea on how to mark a control as selected
//private async void deleteRoomToolStripMenuItem_Click(object sender, EventArgs e)
//{
// if (lbRooms.SelectedItems.Count > 0)
// {
// string? itemSelected = (string?)lbRooms.SelectedItems[lbRooms.SelectedItems.Count - 1];
// if (itemSelected != null)
// {
// var dialogResult = MessageBox.Show("Are You Sure You Want To Delete This Room?\nThis will kick everyone currently in the room out.",
// "are you sure..?",
// MessageBoxButtons.YesNo,
// MessageBoxIcon.Question);
if (dialogResult == DialogResult.Yes)
{
// get the room
var room = RoomList.FirstOrDefault(e => e.Name == itemSelected);
if (room != null)
{
var apiResult = await _apiService.DeleteRoomAsync(room.Id);
if (apiResult != null && apiResult.Success)
MessageBox.Show("Deleted!");
else
MessageBox.Show("There was an error deleting the room. Try Again?", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else MessageBox.Show("This room is unknown. It may have already been deleted.");
}
}
}
}
// if (dialogResult == DialogResult.Yes)
// {
// // get the room
// var room = RoomList.FirstOrDefault(e => e.Name == itemSelected);
// if (room != null)
// {
// var apiResult = await _apiService.DeleteRoomAsync(room.Id);
// if (apiResult != null && apiResult.Success)
// MessageBox.Show("Deleted!");
// else
// MessageBox.Show("There was an error deleting the room. Try Again?", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
// }
// else MessageBox.Show("This room is unknown. It may have already been deleted.");
// }
// }
// }
//}
private async void deleteUserToolStripMenuItem_Click(object sender, EventArgs e)
{
@ -539,9 +590,6 @@ namespace qtc_net_client_2
LoggingService.LogString($"Logged In As '{_apiService.CurrentUser.Username}'");
LoggingService.LogString("Starting SignalR Connection...");
// start gateway connection
await _gatewayService.StartAsync();
// subscribe to gateway events
_gatewayService.OnServerReconnecting += _gatewayService_OnServerReconnecting;
_gatewayService.OnServerReconnected += _gatewayService_OnServerReconnected;
@ -555,6 +603,9 @@ namespace qtc_net_client_2
_apiService.OnCurrentUserUpdate += _apiService_OnCurrentUserUpdate;
// start gateway connection
await _gatewayService.StartAsync();
if (_gatewayService.HubConnection != null && _gatewayService.HubConnection.State == Microsoft.AspNetCore.SignalR.Client.HubConnectionState.Connected)
{
LoggingService.LogString("Connected To SignalR Succesfully.");
@ -571,13 +622,29 @@ namespace qtc_net_client_2
tbcMain.Enabled = true;
var pfpRes = await _apiService.GetUserProfilePic(_apiService.CurrentUser.Id);
var cosmeticRes = await GetCosmeticImage(_apiService.CurrentUser.ActiveProfileCosmetic);
// TODO - refactor this a bit
if (pfpRes.Success && pfpRes.Data != null)
{
using (var ms = new MemoryStream(pfpRes.Data))
using var pfpMS = new MemoryStream(pfpRes.Data);
var pfp = (Bitmap)Image.FromStream(pfpMS);
if (cosmeticRes != null)
{
pbUserPfp.Image = Image.FromStream(ms);
ms.Dispose();
using var cosmeticMS = new MemoryStream(cosmeticRes);
var cosmetic = (Bitmap)Image.FromStream(cosmeticMS);
pbUserPfp.Image = _imgFactory.CreateProfileImage(null, pfp, cosmetic);
}
else pbUserPfp.Image = _imgFactory.CreateProfileImage(null, pfp, null);
}
else if (cosmeticRes != null)
{
using var cosmeticMS = new MemoryStream(cosmeticRes);
var cosmetic = (Bitmap)Image.FromStream(cosmeticMS);
pbUserPfp.Image = _imgFactory.CreateProfileImage(null, null, cosmetic);
}
if (lvUserDirectory.Items.Count <= 0)
@ -627,7 +694,7 @@ namespace qtc_net_client_2
{
LoggingService.LogString("Current User Is An Admin. Using Admin Context Menu Strips...");
lvUserDirectory.ContextMenuStrip = ctxmAdminUserList;
lbRooms.ContextMenuStrip = ctxmAdminRoomList;
flpRooms.ContextMenuStrip = ctxmAdminRoomList;
}
LoggingService.LogString("Client Ready");
@ -674,21 +741,45 @@ namespace qtc_net_client_2
{
await Invoke(async delegate ()
{
lbRooms.Items.Clear();
flpRooms.Controls.Clear();
// always add lobby room to rooms list
var lobbyCtrl = new RoomEntryControl
{
RoomName = "Lobby",
HideUserCount = true,
BackColor = flpRooms.BackColor
};
lobbyCtrl.Margin = new Padding(0, 4, 0, 4);
lobbyCtrl.Width = flpRooms.ClientSize.Width - flpRooms.Padding.Horizontal;
lobbyCtrl.OnRoomDoubleClicked += OnRoomDoubleClicked;
flpRooms.Controls.Add(lobbyCtrl);
var roomsRes = await _apiService.GetAllRoomsAsync();
if (roomsRes.Success && roomsRes.Data != null)
{
foreach (var room in roomsRes.Data)
{
lbRooms.Items.Add(room.Name);
// create room entry
var ctrl = new RoomEntryControl
{
RoomName = room.Name,
RoomUserCount = room.UserCount, // placeholder
BackColor = flpRooms.BackColor
};
ctrl.Margin = new Padding(0, 4, 0, 4);
ctrl.Width = flpRooms.ClientSize.Width - flpRooms.Padding.Horizontal;
ctrl.OnRoomDoubleClicked += OnRoomDoubleClicked;
flpRooms.Controls.Add(ctrl);
}
RoomList = roomsRes.Data;
if (System.Diagnostics.Debugger.IsAttached || _config.EnableDebugLogs)
LoggingService.LogModel(roomsRes.Data);
}
// always add lobby room to rooms list
lbRooms.Items.Add("Lobby");
});
}
}
@ -701,8 +792,8 @@ namespace qtc_net_client_2
{
await Invoke(async delegate ()
{
lvContacts.Items.Clear();
Contacts.Clear();
flpContacts.Controls.Clear();
lblRequestNotif.Visible = false;
var contactsRes = await _apiService.GetCurrentUserContacts();
if (contactsRes.Success && contactsRes.Data != null)
@ -720,26 +811,41 @@ namespace qtc_net_client_2
else if (contact.UserId == _apiService.CurrentUser!.Id)
user = await _apiService.GetUserInformationAsync(contact.OwnerId);
var ctrl = new ContactEntryControl();
if (user.Data != null)
{
Contacts.Add(contact);
switch(user.Data.Status)
{
case 0:
ctrl.StatusColor = Color.Gray;
break;
case 1:
ctrl.StatusColor = Color.LightGreen;
break;
case 2:
ctrl.StatusColor = Color.Gold;
break;
case 3:
ctrl.StatusColor = Color.Red;
break;
}
if (contact.OwnerId == _apiService.CurrentUser!.Id)
{
switch (contact.OwnerStatus)
{
case Contact.ContactStatus.AwaitingApprovalFromOther:
var lvi = lvContacts.Items.Add($"{user.Data.Username} [Request Sent]");
ctrl.Username = $"{user.Data.Username} [Request Sent]";
await AddProfilePicToList(user.Data.Id);
if (ilProfilePics.Images.ContainsKey(user.Data.Id))
lvi.ImageKey = user.Data.Id;
else lvi.ImageKey = "DEFAULT";
ctrl.Avatar = ilProfilePics.Images[user.Data.Id] ?? ilProfilePics.Images[0];
break;
case Contact.ContactStatus.Accepted:
var lvi2 = lvContacts.Items.Add($"{user.Data.Username}");
ctrl.Username = user.Data.Username;
await AddProfilePicToList(user.Data.Id);
if (ilProfilePics.Images.ContainsKey(user.Data.Id))
lvi2.ImageKey = user.Data.Id;
else lvi2.ImageKey = "DEFAULT";
ctrl.Avatar = ilProfilePics.Images[user.Data.Id] ?? ilProfilePics.Images[0];
break;
}
}
@ -748,22 +854,24 @@ namespace qtc_net_client_2
switch (contact.UserStatus)
{
case Contact.ContactStatus.AwaitingApprovalFromSelf:
var lvi = lvContacts.Items.Add($"{user.Data.Username} [Contact Request]");
ctrl.Username = $"{user.Data.Username} [Contact Request]";
await AddProfilePicToList(user.Data.Id);
if (ilProfilePics.Images.ContainsKey(user.Data.Id))
lvi.ImageKey = user.Data.Id;
else lvi.ImageKey = "DEFAULT";
ctrl.Avatar = ilProfilePics.Images[user.Data.Id] ?? ilProfilePics.Images[0];
AudioService.PlaySoundEffect("sndContactRequest");
break;
case Contact.ContactStatus.Accepted:
var lvi2 = lvContacts.Items.Add($"{user.Data.Username}");
ctrl.Username = user.Data.Username;
await AddProfilePicToList(user.Data.Id);
if (ilProfilePics.Images.ContainsKey(user.Data.Id))
lvi2.ImageKey = user.Data.Id;
else lvi2.ImageKey = "DEFAULT";
ctrl.Avatar = ilProfilePics.Images[user.Data.Id] ?? ilProfilePics.Images[0];
break;
}
}
// add the control to the flow panel
ctrl.Margin = new Padding(0, 4, 0, 4);
ctrl.Width = flpContacts.ClientSize.Width - flpContacts.Padding.Horizontal;
ctrl.ContactDoubleClicked += Ctrl_ContactDoubleClicked;
flpContacts.Controls.Add(ctrl);
}
}
@ -774,6 +882,50 @@ namespace qtc_net_client_2
}
}
private async void Ctrl_ContactDoubleClicked(object? sender, EventArgs e)
{
var ctrl = sender as ContactEntryControl;
string? selectedUser = ctrl?.Username;
if (selectedUser != null)
{
// split from [ if it exists
if (selectedUser.Contains('[')) selectedUser = selectedUser.Split('[', options: StringSplitOptions.TrimEntries)[0];
// get user info and open profile dialog
var user = UserDirectory.FirstOrDefault(e => e.Username == selectedUser);
var res = await _apiService.GetUserInformationAsync(user!.Id);
var pfpRes = await _apiService.GetUserProfilePic(user!.Id);
// get cosmetic
byte[]? cosmeticData = null;
if (user.ProfileCosmeticId != 0)
{
var storeRes = await _apiService.GetStoreItem(user.ProfileCosmeticId);
if (storeRes != null && storeRes.Success && storeRes.Data != null)
{
using var client = new HttpClient();
using var response = await client.GetAsync(storeRes.Data.AssetUrl);
if (response.IsSuccessStatusCode)
{
cosmeticData = await response.Content.ReadAsByteArrayAsync();
}
else LoggingService.LogString($"Could Not Get User Cosmetic.\nStatus Code: {response.StatusCode}");
}
}
if (pfpRes != null && !pfpRes.Success) LoggingService.LogString($"User Has No Profile Picture Or It Could Not Be Loaded.\n{pfpRes.Message}");
if (res.Data != null && res.Success)
{
LoggingService.LogString($"Opening Profile For User '{res.Data.Username}'");
Profile frmProfile = new Profile(res.Data, pfpRes, Contacts, _apiService, _gatewayService, cosmeticData);
frmProfile.Show();
}
}
}
private async Task StartRequestNotifBlankLoop(Label label)
{
while (true)
@ -828,6 +980,25 @@ namespace qtc_net_client_2
}
}
private async Task<byte[]?> GetCosmeticImage(int profileCosmeticId)
{
if (profileCosmeticId <= 0) return null;
var storeRes = await _apiService.GetStoreItem(profileCosmeticId);
if (storeRes != null && storeRes.Success && storeRes.Data != null)
{
using var client = new HttpClient();
using var response = await client.GetAsync(storeRes.Data.AssetUrl);
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsByteArrayAsync();
}
else LoggingService.LogString($"Could Not Get User Cosmetic.\nStatus Code: {response.StatusCode}");
}
return null;
}
public void RefreshCurrencyCounter()
{
if (IsHandleCreated && !IsDisposed)
@ -962,7 +1133,7 @@ namespace qtc_net_client_2
if (existingForm != null && existingForm.User.Id == args.User.Id)
{
// we want to just add to its text box
existingForm.Messages.Add($"[{args.User.Username}] {args.Message.Content}\n");
existingForm.Messages.Add($"{args.User.Username}: {args.Message.Content}");
}
else
{

View File

@ -120,73 +120,94 @@
<metadata name="ctxmRefresh.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>356, 21</value>
</metadata>
<metadata name="ilProfilePics.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
<metadata name="ilTabIcons.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>20, 44</value>
</metadata>
<data name="ilProfilePics.ImageStream" mimetype="application/x-microsoft.net.object.binary.base64">
<data name="ilTabIcons.ImageStream" mimetype="application/x-microsoft.net.object.binary.base64">
<value>
AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAA0A0AAAJNU0Z0AUkBTAMBAQAB
mAEBAZgBAQEgAQABIAEABP8BIQEACP8BQgFNATYHAAE2AwABKAMAAYADAAEgAwABAQEAASAGAAFAEgAD
rQH/A7oB/wO6Af8DuQH/A7oB/wO6Af8D2gX/A/wB/wP+Df8D/QH/A/wR/wP8Af8D/g3/A/0B/wPZAf8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af//AIEAA58B/wO6Af8DugH/A7oB/wO6Af8DugH/A9oJ/wP9Af8D
/g3/A/0B/wP9Ef8D/AH/A/4N/wPaAf8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af//AIEAA6IB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A9oN/wP8Af8D/iX/A/wN/wPaAf8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af//
AIEAA6UB/wO6Af8DugH/A7oB/wO6Af8DugH/A9kR/wP+Ff8D/R3/A9oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB//8AgQADpAH/A7kB/wO6Af8DugH/A7oB/wO6Af8D2QH/A/wV/wP+Df8D/QH/A/0R/wP+Af8D
/gH/A9oB/wO6Af8DugH/A7kB/wO6Af8DugH/A7oB//8AgQADoQH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
2gH/A/4B/wP9Ef8D/AH/A/4N/wP9Af8D/RH/A/wB/wPZAf8DugH/A7oB/wO6Af8DuQH/A7oB/wO6Af//
AIEAA58B/wO6Af8DugH/A7oB/wO6Af8DugH/A9oF/wP9Af8D/RH/A/0B/wP+Df8D/QH/A/0R/wPZAf8D
ugH/A7oB/wO6Af8DugH/A7kB/wO6Af//AIEAA7EB/wO6Af8DugH/A7oB/wO6Af8DugH/A9MJ/wP+Ff8D
/AH/A/4h/wPTAf8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af//AIEAA7oB/wO6Af8DugH/A7oB/wO6Af8D
uQH/A8AB/wP9Df8D/hH/A/4V/wP9Bf8D/QH/A8AB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQAD
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A9oN/wP+Af8D/RX/A/4N/wP9Af8D/AH/A9oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af//AIEAA7oB/wO5Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
3Q3/A/0B/wP9Ef8D/QH/A/4N/wPcAf8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQAD
ugH/A7oB/wO5Af8DuQH/A7oB/wO6Af8DugH/A7oB/wO5Af8DyQH/A+wB/wP+Bf8D/gH/A/wR/wP9Af8D
/QH/A+wB/wPKAf8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af//AIEAA7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7kB/wO6Af8DwQH/A9IB/wPfAf8D5gH/A+oB/wPrAf8D
5wH/A98B/wPSAf8DwAH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af//
AIEAA7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
vQH/A8cB/wPGAf8DvQH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af//AIEAA7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A8IB/wPnAf8D/QX/A/4B/wP6Af8D5gH/A8IB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB//8AgQADugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wPIAf8D+QH/A/0N/wP9Af8D/QH/A/oB/wPIAf8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO5Af8DugH/A7oB//8AgQADugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A74B/wP4Bf8D/AH/A/4N/wP9Af8D/AH/A/gB/wO+Af8DugH/A7oB/wO6Af8DuQH/A7oB/wO6Af8D
ugH/A7oB/wO5Af8DugH//wCBAAO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7kB/wO6Af8D
2w3/A/0B/wP9Df8D/QH/A/4B/wPbAf8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH//wCBAAO6Af8DugH/A7oB/wO6Af8DugH/A7kB/wO6Af8DugH/A7oB/wO6Af8D8BH/A/wB/wP+Ef8D
8AH/A7oB/wO6Af8DugH/A7oB/wO5Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQADugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A/gB/wP9Jf8D+AH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB//8AgQADugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A/QB/wP9Af8D/BH/A/4B/wP+Cf8D9QH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB//8AgQADugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A+UF/wP+Af8D
/BH/A/wB/wP9Bf8D5QH/A7oB/wO5Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQAD
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DuQH/A8gB/wP+Bf8D/gH/A/wR/wP9Af8D
/QH/A8gB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7kB/wO6Af//AIEAA7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D3Qn/A/4V/wPcAf8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQADugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D2QH/A/wJ/wP+Bf8D/AH/A9kB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQADugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A8AB/wPWAf8D4gH/A+EB/wPVAf8DwAH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQADugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7kB/wO6Af8DugH/A7oB/wO6Af8DugH/A7kB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQAD
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO5Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO5Af8D
uQH/A7oB//8AgQADugH/A7oB/wO6Af8DuQH/A7oB/wO6Af8DugH/A7oB/wO5Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO5Af8D
ugH/A7oB/wO6Af8DugH/A7oB//8AgQADugH/A7oB/wO6Af8DugH/A7kB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DuQH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQADugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQADugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7kB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQAB
QgFNAT4HAAE+AwABKAMAAYADAAEgAwABAQEAAQEGAAECFgAD//8A/wADAAs=
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAshIAAAJNU0Z0AUkBTAIBAQQB
AAGoAQMBqAEDARABAAEQAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABQAMAASADAAEBAQABIAYAASD/
AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/ACIAA2cB7wJnAVkB7wFnAV0BWQHvAWcBWwFZAe8B
ZwFbAVkB7wFnAlkB7wFnAWQBWQHvA2cB7wNnAe8DZwHvA2cB7wNnAe8DZwHvA2cB7wNnAe8DZwHvAwcB
CQMqAT8DRQF8A1kBuwNjAd8DaAH0A4AB/gOBAf8DgQH/A4EB/wOAAf4DaAH0A2MB3wNaAboDRAF6AycB
OjgAAzMBUQNuAfUIAAM3AVoDWAG4A2MB3wJjAV0B3wFiAl0B3wNdAd8DXQHfAWECXQHfA2MB3wNjAd8D
VQGsAzABSwgAA/gB/wG5AZUBPAH/AYMBfQFuAf8BhAF9AWwB/wGqAYQBJwH/AawBewEAAf8BzAG8AZQB
/wN+Af8DfgH/A34B/wN+Af8DfgH/A34B/wN+Af8DfgH/A44B/wNDAXUDXQHMA3wB+AOBAf8DgQH/A4EB
/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A3wB+ANUAag4AAMSARgDPwFtBAADOwFiA10B
xQNoAfQBnwFlATEB/wGXAVMBFwH/AZYBSwEJAf8BkwFGAQEB/wGMAUMBAwH/AX0BQAELAf8BawFAARoB
/wFuAVABNgH/A2gB8ANaAbcDNAFUBAAE/wGXAYsBbQH/AoEBgAH/AYIBgQGAAf8BmAGIAWAB/wHKAZAB
AAH/Ad0BzAGfAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOTAf8DagHtA30B+gOBAf8D
gQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DVQGvNAADXwHTAz0B
ZwQAAzUBVQNdAccCbgFaAfUBuAFlARsB/wG5AVgBAgH/AckBXwEAAf8B2AFlAQAB/wHcAWcBAAH/AdYB
ZAEAAf8BwwFcAQAB/wGiAUwBAAH/AXwBOwEDAf8BbgFGASMB/wNoAfADWgG3AzABSgT/AYYBhAF9Af8D
gQH/A4EB/wGHAYMBegH/Ac8BlAEAAf8B3gHMAZ8B/wPgAf8D4AH/A+AB/wPgAf8D4AH/A+AB/wPgAf8D
4AH/A7wB/wNjAd8DbgH1A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8D
gQH/A4EB/wNVAa80AANaAcIDNAFTBAADXAHEAnwBXAH4AdQBcQEYAf8B1wFlAQAB/wHlAWwBAAH/AfIB
cgEAAf8B+gF1AQAB/wH8AXYBAAH/AfoBdgEAAf8B8wFyAQAB/wHiAWsBAAH/Ab0BWQEAAf8BhwFAAQAB
/wFxAUgBIwH/A2gB8ANWAasE/wGLAYYBegH/A4EB/wOBAf8BjgGGAXEB/wHPAZQBAAH/Ad4BzAGfIf8D
ygH/AzYBWANbAcADbgH1A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8D
aAH0A1IBpBAAAw0BEQM/AWwDUwGnAVwCWQG+AVgCVgGzAUgCRwGDAyEBMAQAA28B8wM6AWAIAAH+Ad0B
wQH/Ae0BgAEgAf8B7QFxAQIB/wHzAXMBAAH/AfoBdgEAAf8B/gF4AQAC/wF7AQgC/wGIAScC/wGiAVMB
/wH+AYEBFwH/AfwBeAEEAf8B7AFvAQAB/wHBAVsBAAH/AYYBQQEDAf8BeAFWATYB/wNjAd8E/wGsAZYB
YAH/AYMBggF/Af8BhQGCAX0B/wGzAZMBRAH/Ac8BlAEAAf8B3gHMAZ8B/wOwAf8DsAH/A7AB/wOwAf8D
sAH/A7AB/wOwAf8DsAH/A6gB/wMCAQMDGgEjAzgBXANUAagDYgHXA3AB8QOAAf4DgQH/A4EB/wOBAf8D
gQH9A2gB8ANhAdQDUwGlAzYBWQMYASAIAAMaASQDUgGgAmMBSAH2AaIBcwEAAf8BrgF8AQAB/wGwAX0B
AAH/AagBeAEAAf8BlQFqAQAB/wKAAXUB/gFcAlkBxgNXAbUDFgEeCAAB/wGyAW8B/wH9AYABEQH/AfwB
dwEBAf8B/QF3AQAC/wF4AQAC/wF/AQ8C/wGSATsC/wGzAYMC/wHqAeAC/wGQAT0C/wF7AQoB/wH8AXcB
AAH/AeUBbAEAAf8BsQFUAQAB/wGEAUsBGgH/A2MB3wT/AdkBqgE3Af8BvgGYATgB/wHAAZgBNgH/AdwB
ogEUAf8BzwGUAQAB/wHeAcwBnwH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DkwH/RAAD
IAEtAmMBWgHpAb8BiAEAAf8BzQGVAQoB/wGwAYgBJwH/AXMBZAE/Af8BTQFLAUcB/wFOAUsBQgH/AWYB
VwExAf8BmgF0ARcB/wGkAXYBAwH/AXABTwEAAf8DQwF2BAEEAAH/AZoBQgL/AYMBFQH/Af4BegEEAv8B
eAEAAv8BeAEAAv8BlQE/Av8BygGuAv8B2gHGAv8B7QHlAv8BlgFJAv8BfAENAf8B/gF4AQAB/wH0AXMB
AAH/AdABYgEAAf8BmgFOAQoB/wFjAl0B3wT/AeEBrgExAf8BvQGXATsB/wHAAZgBNQH/AeMBpQEKAf8B
zwGUAQAB/wHeAcwBnwH/A8AB/wPAAf8DwAH/A8AB/wPAAf8DwAH/A8AB/wPAAf8DrwH/CAADAgEDAwgB
CgMhAS8DMQFOAz0BaANDAXYDRAF6A0MBdQM9AWcDMQFNAyABLgMHAQkEAggAAmMBWgHpAdkBmgEAAf8B
2gGjARwB/wKOAYwB/wOKAf8DlwH/A5sB/wORAf8DdAH/A0gB/wFDAUIBPwH/AbUBgwEHAf8BegFXAQAB
/wM2AVgEAAH/AZUBNwL/AYkBHwL/AX0BCAL/AXgBAAL/AXgBAAL/AagBXAL/AeABzQL/AaEBZgL/AdgB
xQL/AbkBlAL/AYcBIwL/AXgBAAH/AfsBdgEAAf8B4gFqAQAB/wGvAVQBAwH/AWMCXQHfBP8BuwGdAVMB
/wGIAYQBeQH/AYwBhQF0Af8BxAGZATAB/wHPAZQBAAH/Ad4BzAGfIf8DygH/BAADEwEaAzkBXQNZAbwD
ZAHbA2oB7QNjAfYDXwH7A4EB/QNfAfsDYwH2A2UB7ANjAdoDWgG6AzgBXAMTARoDQwF2AekBpwECAf8B
6QGrARIB/wHQAcoBuwH/A6wB/wNdAf8DTAH/A0sB/wNEAf8DDwH/A7MB/wNmAf8BVAFMAToB/wGuAX0B
BAH/A10BzAQAAf8BoAFJAv8BkgExAv8BgQERAv8BeQEDAv8BeAEAAv8BqAFcAv8B4AHNAv8BoQFmAv8B
2AHFAv8BwAGfAv8BiQEnAv8BeAEAAf8B/gF4AQAB/wHsAW8BAAH/Ab8BWgECAf8BYwJdAd8E/wGUAYoB
cwH/A4EB/wOBAf8BmgGKAWMB/wHPAZQBAAH/Ad4BzAGfAf8D0AH/A9AB/wPQAf8D0AH/A9AB/wPQAf8D
0AH/A9AB/wO1Af8DGgEkA1YBrgNoAfQDgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8D
gQH/A4EB/wNrAfIDUgGhAmoBYQHmAe0BrQEQAf8B9AHQAXYB/wP6Af8D+gH/A30B/wN/Af8DgAH/A4AB
/wN+Af8DhAH/A7sB/wNqAf8BqAGAARwB/wJjAUgB9gQAAf8BswFvAv8BngFIAv8BiAEeAv8BfAEHAv8B
eAEAAv8BmAFDAv8BzgG0Av8B1wHAAv8B6gHgAv8BnQFXAv8BfgERAv8BeAEAAv8BeAEAAf8B8AFxAQAB
/wHLAWQBCQH/AWMBYQFdAd8E/wGGAYMBfgH/A4EB/wOBAf8BhgGDAXsB/wHPAZQBAAH/Ad4BzAGfAf8D
gQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOTAf8DVwGyA2UB5wOBAf8DgQH/A4EB/wOBAf8D
gQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DVQGvA2IB7gHvAbQBIQH/AfcB3AGXCf8D
kQH/A4gB/wOHAf8DhwH/A4EB/wNXAf8D5gH/A6MB/wG2AZEBNgH/AmoBQQH5BAAB/wHMAZ8C/wGsAWMC
/wGTATMC/wGBAREC/wF5AQIC/wGCARYC/wGaAUsC/wGuAXgC/wGlAVcC/wGBARcC/wF5AQQC/wF4AQAC
/wF4AQAB/wHwAXEBAAH/AdUBcQEXAf8CYwFdAd8E/wGLAYYBeQH/A4EB/wOBAf8BjgGGAXEB/wHPAZQB
AAH/Ad4BzAGfAf8DoQH/A6EB/wOhAf8DoQH/A6EB/wOhAf8DoQH/A6EB/wOhAf8DbwHzA18B+wOBAf8D
gQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DVQGvA0sBjQHwAb4B
PwH/AfQBzQFsIf8D+wH/A9AB/wHXAacBMQH/AmEBXQHRBAAB/wHpAdUC/wG8AYEC/wGkAVQC/wGOASoC
/wF/AQ0C/wF5AQIC/wF7AQkC/wGCAR0C/wF4AQAC/wF4AQAC/wF4AQEC/wF6AQQC/wF6AQMB/wHzAXQB
AwH/AeIBhAEyAf8DYwHfBP8BpwGUAWcB/wGDAYIBfwH/AYUBgwF+Af8BsAGUAU4B/wHTAZcBAgH/AeAB
zgGfAf8D5wH/A+cB/wPnAf8D5wH/A+cB/wPnAf8D5wH/A+cB/wPAAf8DZAHbA2gB9AOBAf8DgQH/A4EB
/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DVQGvAwcBCQNiAe4B8QG8ATsB
/wH6AeoBwgH/A9wB/wN3Af8DaAH/A2gB/wNoAf8DMgn/AfIB3QGpAf8B6gGpAQgB/wM+AWoEAANeAdID
agH5Af8BuwF9Av8BowFSAv8BkAEsAv8BggETAv8BfQEIAv8BegEEAv8BeQECAv8BegEEAv8BfQEJAv8B
gAEPAv8BfwENAf8B+AGGASAB/wNoAfQDWAG4BP8B1wGxAVIB/wGaAY8BdAH/AaABkgFtAf8B4AGvATcB
/wHnAakBEAH/AesB1QGgAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOTAf8DPAFkA18B
yQN9AfoDgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wN9AfoDVQGqBAAD
MwFRA2gB8AHzAcYBWAH/AfoB5wG4Fv8B/gH7Af8B+QHiAaoB/wHvAbgBLQH/A04BlgQCBAADPAFmA2MB
1QN8AfgB/wG+AYUC/wGqAV8C/wGZAT4C/wGNAScC/wGGARoC/wGDARUC/wGFARkC/wGKASIC/wGNASgC
/wGTATMB/wJuAWgB9QNdAcUDNgFZBP8B9AHNAWwB/wH0AcsBZgH/AfQBywFlAf8B9AHLAWUB/wHxAcEB
SQH/AfkB4wGsAf8DiQH/A4kB/wOJAf8DiQH/A4kB/wOJAf8DiQH/A4kB/wOaAf8DBgEIAzEBTANQAZsD
ZQHsA30B+gOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DfQH6A2oB7QNQAZsDLwFJCAADIgExA18B
yQJ9AWcB+gHzAcoBZQH/AfkB4QGmAf8B+wHtAcwB/wH7AewByAH/AfgB3QGbAf8DgAH+AmUBXgHiAz0B
aAQBDAADQgFyA2MB1QNqAfkB/wHJAZkC/wG8AX8C/wGuAWYC/wGkAVMC/wGfAUoC/wGfAUsC/wGjAVEC
/wGnAVgB/wN8AfgDXQHHAzsBYgQAQP8IAAMFAQYDEgEXAzoBYANRAZ8DXwHTA2cB7wNjAfYDYgHuA14B
0gNRAZ4DOQFfAxEBFgMFAQYUAAMPARMDRwGCA2QB2wJ+AW8B/ANnAeoDVAGoAygBOxwAAzwBZQNeAdIB
/wHvAeAC/wHcAbwC/wHNAZ8C/wHBAYoC/wG7AX8C/wG/AYYC/wHNAaEC/wHpAdYB/wNcAcQDNQFVCAAB
QgFNAT4HAAE+AwABKAMAAUADAAEgAwABAQEAAQEGAAEBFgAD/4UAAf8B/AHAAQMEAAH/AfwBgAEBBAAB
/wH5BgAB/wH5BgAB8AETBgABwAEDBAAC/wGAAQEEAAHAAQEBgAEBBAABgAIAAQEHAAEBBwABAQcAAQEH
AAEBBgABgAEBBgABwAEDAYABAQIAAcABAQHwAR8BwAEDCw==
</value>
</data>
<metadata name="ilStatusIcons.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
@ -196,31 +217,31 @@
<value>
AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAohMAAAJNU0Z0AUkBTAIBAQQB
AAFQAQEBUAEBARABAAEQAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABQAMAASADAAEBAQABIAYAASD/
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAihMAAAJNU0Z0AUkBTAIBAQQB
AAHoAQEB6AEBARABAAEQAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABQAMAASADAAEBAQABIAYAASD/
AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AC4AAwYBBwM0AVQDUQGiA14B0gNaAekDYAHoA10B
0QNQAZ8DMQFNAwUBBhgAAwYBBwM0AVQDUQGiA14B0gNaAekDYAHoA10B0QNQAZ8DMQFNAwUBBhgAAwYB
BwM0AVQDUQGiA14B0gNaAekDYAHoA10B0QNQAZ8DMQFNAwUBBhgAAwYBBwM0AVQDUQGiA14B0gNaAekD
YAHoA10B0QNQAZ8DMQFNAwUBBhQAAyABLQNUAasDWwHkA1oB9QMkAfsDTgH+A04B/gMkAfsDUwH0A2IB
4QNRAaEDHgEqEAADIAEtA1QBqwNbAeQDWgH1ASEBXgEhAfsBKgFqASoB/gEqAWoBKgH+ASEBXgEhAfsD
UwH0A2IB4QNRAaEDHgEqEAADIAEtA1QBqwNbAeQDWgH1ASECXgH7ASoCagH+ASoCagH+ASECXgH7A1MB
9ANiAeEDUQGhAx4BKhAAAyABLQNUAasDWwHkA1oB9QIhAV4B+wIqAWoB/gIqAWoB/gIhAV4B+wNTAfQD
YgHhA1EBoQMeASoMAAMbASUDWAG9A1oB8gNSAf4DMAH/AzkB/wM8Af8DNgH/AyoB/wMkAf8DQAH9A14B
8ANWAbIDGgEjCAADGwElA1gBvQNaAfIBKgFyASoB/gEAAVcBAAH/AQABZwEAAf8BAAFsAQAB/wEAAWEB
AAH/AQABTAEAAf8BAAFAAQAB/wNAAf0DXgHwA1YBsgEZARoBGQEjCAADGwElA1gBvQNaAfIBKgJyAf4B
YAHoA10B0QNQAZ8DMQFNAwUBBhQAAyABLQNUAasDWwHkA1oB9QMkAfsDYQH+A2EB/gMkAfsDUwH0A2IB
4QNRAaEDHgEqEAADIAEtA1QBqwNbAeQDWgH1ASEBXgEhAfsBPQF9AT0B/gE9AX0BPQH+ASEBXgEhAfsD
UwH0A2IB4QNRAaEDHgEqEAADIAEtA1QBqwNbAeQDWgH1ASECXgH7AT0CfQH+AT0CfQH+ASECXgH7A1MB
9ANiAeEDUQGhAx4BKhAAAyABLQNUAasDWwHkA1oB9QIhAV4B+wI9AX0B/gI9AX0B/gIhAV4B+wNTAfQD
YgHhA1EBoQMeASoMAAMbASUDWAG9A1oB8gNlAf4DMAH/AzkB/wM8Af8DNgH/AyoB/wMkAf8DQAH9A14B
8ANWAbIDGgEjCAADGwElA1gBvQNaAfIBPQGAAT0B/gEAAVcBAAH/AQABZwEAAf8BAAFsAQAB/wEAAWEB
AAH/AQABTAEAAf8BAAFAAQAB/wNAAf0DXgHwA1YBsgEZARoBGQEjCAADGwElA1gBvQNaAfIBPQKAAf4B
AAJXAf8BAAJnAf8BAAJsAf8BAAJhAf8BAAJMAf8BAAJAAf8DQAH9A14B8ANWAbIBGQIaASMIAAMbASUD
WAG9A1oB8gIqAXIB/gIAAVcB/wIAAWcB/wIAAWwB/wIAAWEB/wIAAUwB/wIAAUAB/wNAAf0DXgHwA1YB
sgIZARoBIwQAAwMBBANSAaUDYAHzA0kB/wNVAf8DZQH/A3EB/wN1Af8DcQH/A2QB/wNMAf8DMQH/A04B
WAG9A1oB8gI9AYAB/gIAAVcB/wIAAWcB/wIAAWwB/wIAAWEB/wIAAUwB/wIAAUAB/wNAAf0DXgHwA1YB
sgIZARoBIwQAAwMBBANSAaUDYAHzA0kB/wNVAf8DZQH/A3EB/wN1Af8DcQH/A2QB/wNMAf8DMQH/A2EB
/gNiAe4DUAGaAwMBBAMDAQQBUgFTAVIBpQFgAW8BYAHzAQABggEAAf8BAAGZAQAB/wEAAbYBAAH/AQAB
zAEAAf8BAAHTAQAB/wEAAcsBAAH/AQABswEAAf8BAAGIAQAB/wEAAVcBAAH/ASoBagEqAf4DYgHuA1AB
zAEAAf8BAAHTAQAB/wEAAcsBAAH/AQABswEAAf8BAAGIAQAB/wEAAVcBAAH/AT0BfQE9Af4DYgHuA1AB
mgMDAQQDAwEEAVICUwGlAWACbwHzAQACggH/AQACmQH/AQACtgH/AQACzAH/AQAC0wH/AQACywH/AQAC
swH/AQACiAH/AQACVwH/ASoCagH+A2IB7gNQAZoDAwEEAwMBBAJSAVMBpQJgAW8B8wIAAYIB/wIAAZkB
/wIAAbYB/wIAAcwB/wIAAdMB/wIAAcsB/wIAAbMB/wIAAYgB/wIAAVcB/wIqAWoB/gNiAe4DUAGaAwMB
swH/AQACiAH/AQACVwH/AT0CfQH+A2IB7gNQAZoDAwEEAwMBBAJSAVMBpQJgAW8B8wIAAYIB/wIAAZkB
/wIAAbYB/wIAAcwB/wIAAdMB/wIAAcsB/wIAAbMB/wIAAYgB/wIAAVcB/wI9AX0B/gNiAe4DUAGaAwMB
BAMtAUQDYAHoA4AB/gNuAf8DewH/A4UB/wOKAf8DjAH/A4oB/wOFAf8DdgH/A1cB/wMyAf8DQAH9A14B
3QMqAT8DLQFEAWABaQFgAegBKgGAASoB/gEAAcYBAAH/AQAB3AEAAf8BAAHuAQAB/wEAAfgBAAH/AQAB
3QMqAT8DLQFEAWABaQFgAegBPQGAAT0B/gEAAcYBAAH/AQAB3AEAAf8BAAHuAQAB/wEAAfgBAAH/AQAB
+wEAAf8BAAH5AQAB/wEAAe8BAAH/AQAB1AEAAf8BAAGcAQAB/wEAAVoBAAH/A0AB/QNeAd0DKgE/Ay0B
RAFgAmkB6AEqAoAB/gEAAsYB/wEAAtwB/wEAAu4B/wEAAvgB/wEAAvsB/wEAAvkB/wEAAu8B/wEAAtQB
/wEAApwB/wEAAloB/wNAAf0DXgHdAyoBPwMtAUQCYAFpAegCKgGAAf4CAAHGAf8CAAHcAf8CAAHuAf8C
RAFgAmkB6AE9AoAB/gEAAsYB/wEAAtwB/wEAAu4B/wEAAvgB/wEAAvsB/wEAAvkB/wEAAu8B/wEAAtQB
/wEAApwB/wEAAloB/wNAAf0DXgHdAyoBPwMtAUQCYAFpAegCPQGAAf4CAAHGAf8CAAHcAf8CAAHuAf8C
AAH4Af8CAAH7Af8CAAH5Af8CAAHvAf8CAAHUAf8CAAGcAf8CAAFaAf8DQAH9A14B3QMqAT8DTgGVA3cB
+AN/Af8DhQH/A4oB/wONAf8DjgH/A44B/wOOAf8DjQH/A4kB/wN3Af8DTQH/AyUB/wNaAfIDSgGLA04B
lQFcAXwBXAH4AQAB5QEAAf8BAAHvAQAB/wEAAfgBAAH/AQAB/QEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB
@ -234,53 +255,53 @@
+wH/AQMC/QH/AQAC/gH/AQAD/wEAA/8BAAP/AQAD/wEAA/8BAAL9Af8BAALvAf8BAAK5Af8BAAJdAf8D
QQH5A1oBxAJbAV8B0wIrAX4B/AIOAfsB/wIDAf0B/wIAAf4B/wIAAv8CAAL/AgAC/wIAAv8CAAL/AgAB
/QH/AgAB7wH/AgABuQH/AgABXQH/A0EB+QNaAcQDbgH1A4AB/gOfAf8DkwH/A48B/wOOAf8DjgH/A44B
/wOOAf8DjgH/A44B/wOLAf8DdwH/A0gB/wNAAf0DYgHhAVoBbgFaAfUBTgGrAU4B/gEnAf8BJwH/AQsB
/wOOAf8DjgH/A44B/wOLAf8DdwH/A0gB/wNAAf0DYgHhAVoBbgFaAfUBYQGFAWEB/gEnAf8BJwH/AQsB
/wELAf8BAQH/AQEB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB
/wEAAfkBAAH/AQAB1gEAAf8BAAGBAQAB/wNAAf0DYgHhAVoCbgH1AU4CqwH+AScD/wELA/8BAQP/AQAD
/wEAA/8BAAP/AQAD/wEAA/8BAAP/AQAC+QH/AQAC1gH/AQACgQH/A0AB/QNiAeECWgFuAfUCTgGrAf4C
/wEAAfkBAAH/AQAB1gEAAf8BAAGBAQAB/wNAAf0DYgHhAVoCbgH1AWEChQH+AScD/wELA/8BAQP/AQAD
/wEAA/8BAAP/AQAD/wEAA/8BAAP/AQAC+QH/AQAC1gH/AQACgQH/A0AB/QNiAeECWgFuAfUCYQGFAf4C
JwL/AgsC/wIBAv8CAAL/AgAC/wIAAv8CAAL/AgAC/wIAAv8CAAH5Af8CAAHWAf8CAAGBAf8DQAH9A2IB
4QNjAfYDgAH+A6sB/wOZAf8DkAH/A44B/wOOAf8DjgH/A44B/wOOAf8DjgH/A40B/wN/Af8DVQH/A0AB
/QNeAeIBSAFjAUgB9gFxAasBcQH+AUIB/wFCAf8BGQH/ARkB/wEEAf8BBAH/AQAB/wEAAf8BAAH/AQAB
/QNeAeIBSAFjAUgB9gGAAYUBgAH+AUIB/wFCAf8BGQH/ARkB/wEEAf8BBAH/AQAB/wEAAf8BAAH/AQAB
/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/QEAAf8BAAHkAQAB/wEAAZgBAAH/A0AB
/QNeAeIBSAJjAfYBcQKrAf4BQgP/ARkD/wEEA/8BAAP/AQAD/wEAA/8BAAP/AQAD/wEAA/8BAAL9Af8B
AALkAf8BAAKYAf8DQAH9A14B4gJIAWMB9gJxAasB/gJCAv8CGQL/AgQC/wIAAv8CAAL/AgAC/wIAAv8C
/QNeAeIBSAJjAfYBgAKFAf4BQgP/ARkD/wEEA/8BAAP/AQAD/wEAA/8BAAP/AQAD/wEAA/8BAAL9Af8B
AALkAf8BAAKYAf8DQAH9A14B4gJIAWMB9gKAAYUB/gJCAv8CGQL/AgQC/wIAAv8CAAL/AgAC/wIAAv8C
AAL/AgAC/wIAAf0B/wIAAeQB/wIAAZgB/wNAAf0DXgHiA2EB1gN+AfwDuAH/A6MB/wOTAf8DjgH/A44B
/wOOAf8DjgH/A44B/wOOAf8DjQH/A4IB/wNcAf8DTQH6A1oBxwFcAWEBXAHWAWQBgwFkAfwBXwH/AV8B
/wOOAf8DjgH/A44B/wOOAf8DjQH/A4IB/wNcAf8DTQH6A1oBxwFcAWEBXAHWAWQBfgFkAfwBXwH/AV8B
/wEvAf8BLwH/AQwB/wEMAf8BAQH/AQEB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB
/wEAAf8BAAH+AQAB/wEAAeoBAAH/AQABpQEAAf8BSAFNAUgB+gNaAccBXAJhAdYBZAKDAfwBXwP/AS8D
/wEMA/8BAQP/AQAD/wEAA/8BAAP/AQAD/wEAA/8BAAL+Af8BAALqAf8BAAKlAf8BSAJNAfoDWgHHAlwB
YQHWAmQBgwH8Al8C/wIvAv8CDAL/AgEC/wIAAv8CAAL/AgAC/wIAAv8CAAL/AgAB/gH/AgAB6gH/AgAB
pQH/AkgBTQH6A1oBxwNQAZoDbQH5A8UB/wOyAf8DnAH/A5EB/wOOAf8DjgH/A44B/wOOAf8DjwH/A44B
/wODAf8DYAH/A1oB8gNMAZADUAGaAWoBfwFqAfkBfAH/AXwB/wFRAf8BUQH/AR8B/wEfAf8BBwH/AQcB
/wEBAf8BAQH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQIB/wECAf8BAgH+AQIB/wEAAesBAAH/AQAB
rQEAAf8BWgFrAVoB8gNMAZADUAGaAWoCfwH5AXwD/wFRA/8BHwP/AQcD/wEBA/8BAAP/AQAD/wEAA/8B
AgP/AQIC/gH/AQAC6wH/AQACrQH/AVoCawHyA0wBkANQAZoCagF/AfkCfAL/AlEC/wIfAv8CBwL/AgEC
/wIAAv8CAAL/AgAC/wICAv8CAgH+Af8CAAHrAf8CAAGtAf8CWgFrAfIDTAGQAy8BSQNsAesDgAH+A8YB
/wOuAf8DnAH/A5MB/wOQAf8DjwH/A5AB/wOTAf8DkwH/A4UB/wNAAf0DYAHgAy0BRQMvAUkDbAHrAYAB
qwGAAf4BfwH/AX8B/wFJAf8BSQH/AR8B/wEfAf8BDAH/AQwB/wEFAf8BBQH/AQMB/wEDAf8BBQH/AQUB
/wEKAf8BCgH/AQoB/gEKAf8BAQHtAQEB/wFAAbYBQAH9AWABZgFgAeADLQFFAy8BSQNsAesBgAKrAf4B
fwP/AUkD/wEfA/8BDAP/AQUD/wEDA/8BBQP/AQoD/wEKAv4B/wEBAu0B/wFAArYB/QFgAmYB4AMtAUUD
LwFJA2wB6wKAAasB/gJ/Av8CSQL/Ah8C/wIMAv8CBQL/AgMC/wIFAv8CCgL/AgoB/gH/AgEB7QH/AkAB
tgH9AmABZgHgAy0BRQMDAQQDVgGuA24B9QPZAf8DywH/A7cB/wOnAf8DnQH/A5oB/wOcAf8DnwH/A5sB
/wOJAf8DaAHwA1IBowMDAQQDAwEEA1YBrgNuAfUBqAH/AagB/wGJAf8BiQH/AVwB/wFcAf8BNwH/ATcB
/wEiAf8BIgH/ARsB/wEbAf8BHwH/AR8B/wEmAf8BJgH/AR0B/wEdAf8BBQHzAQUB/wFeAWgBXgHwA1IB
owMDAQQDAwEEA1YBrgNuAfUBqAP/AYkD/wFcA/8BNwP/ASID/wEbA/8BHwP/ASYD/wEdA/8BBQLzAf8B
XgJoAfADUgGjAwMBBAMDAQQDVgGuA24B9QKoAv8CiQL/AlwC/wI3Av8CIgL/AhsC/wIfAv8CJgL/Ah0C
/wIFAfMB/wJeAWgB8ANSAaMDAwEEBAADHAEnA10BxwNjAfYDiwH+A9cB/wPMAf8DwgH/A7sB/wO3Af8D
sQH/A4AB/gNoAfQDWQG8AxsBJggAAxwBJwNdAccDYwH2AYABqwGAAf4BpQH/AaUB/wGLAf8BiwH/AXQB
/wF0Af8BZgH/AWYB/wFcAf8BXAH/AU4B/wFOAf8BWgGrAVoB/gFTAWgBUwH0AVcBWQFXAbwDGwEmCAAD
HAEnA10BxwNjAfYBgAKrAf4BpQP/AYsD/wF0A/8BZgP/AVwD/wFOA/8BWgKrAf4BUwJoAfQBVwJZAbwD
GwEmCAADHAEnA10BxwNjAfYCgAGrAf4CpQL/AosC/wJ0Av8CZgL/AlwC/wJOAv8CWgGrAf4CUwFoAfQC
VwFZAbwDGwEmDAADIQEwA1kBtgNiAe4DfQH6A74B/QPUAf8DzAH/A74B/QNqAfkDbAHrA1UBrAMfASwQ
AAMhATADWQG2A2IB7gN9AfoBrgG+Aa4B/QGfAf8BnwH/AYwB/wGMAf8BTAG+AUwB/QFoAX8BaAH5AWEB
bAFhAesDVQGsAx8BLBAAAyEBMANZAbYDYgHuA30B+gGuAr4B/QGfA/8BjAP/AUwCvgH9AWgCfwH5AWEC
bAHrA1UBrAMfASwQAAMhATADWQG2A2IB7gN9AfoCrgG+Af0CnwL/AowC/wJMAb4B/QJoAX8B+QJhAWwB
6wNVAawDHwEsFAADBgEHAzYBWANVAawDZgHlA34B/AOBAfsDZQHiA1MBpwMzAVEDBgEHGAADBgEHAzYB
WANVAawDZgHlAX4BgwF+AfwBXwGMAV8B+wNlAeIDUwGnAzMBUQMGAQcYAAMGAQcDNgFYA1UBrANmAeUB
fgKDAfwBXwKMAfsDZQHiA1MBpwMzAVEDBgEHGAADBgEHAzYBWANVAawDZgHlAn4BgwH8Al8BjAH7A2UB
4gNTAacDMwFRAwYBBwwAAUIBTQE+BwABPgMAASgDAAFAAwABIAMAAQEBAAEBBgABARYAA/+BAAHgAQcB
4AEHAeABBwHgAQcBwAEDAcABAwHAAQMBwAEDAYABAQGAAQEBgAEBAYABAVAAAYABAQGAAQEBgAEBAYAB
AQHAAQMBwAEDAcABAwHAAQMB4AEHAeABBwHgAQcB4AEHCw==
/wEAAf8BAAH+AQAB/wEAAeoBAAH/AQABpQEAAf8DTQH6A1oBxwFcAmEB1gFkAn4B/AFfA/8BLwP/AQwD
/wEBA/8BAAP/AQAD/wEAA/8BAAP/AQAD/wEAAv4B/wEAAuoB/wEAAqUB/wNNAfoDWgHHAlwBYQHWAmQB
fgH8Al8C/wIvAv8CDAL/AgEC/wIAAv8CAAL/AgAC/wIAAv8CAAL/AgAB/gH/AgAB6gH/AgABpQH/A00B
+gNaAccDUAGaA2oB+QPFAf8DsgH/A5wB/wORAf8DjgH/A44B/wOOAf8DjgH/A48B/wOOAf8DgwH/A2AB
/wNaAfIDTAGQA1ABmgNqAfkBfAH/AXwB/wFRAf8BUQH/AR8B/wEfAf8BBwH/AQcB/wEBAf8BAQH/AQAB
/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQIB/wECAf8BAgH+AQIB/wEAAesBAAH/AQABrQEAAf8BWgFrAVoB
8gNMAZADUAGaA2oB+QF8A/8BUQP/AR8D/wEHA/8BAQP/AQAD/wEAA/8BAAP/AQID/wECAv4B/wEAAusB
/wEAAq0B/wFaAmsB8gNMAZADUAGaA2oB+QJ8Av8CUQL/Ah8C/wIHAv8CAQL/AgAC/wIAAv8CAAL/AgIC
/wICAf4B/wIAAesB/wIAAa0B/wJaAWsB8gNMAZADLwFJA2wB6wOAAf4DxgH/A64B/wOcAf8DkwH/A5AB
/wOPAf8DkAH/A5MB/wOTAf8DhQH/A0AB/QNgAeADLQFFAy8BSQNsAesBgAGFAYAB/gF/Af8BfwH/AUkB
/wFJAf8BHwH/AR8B/wEMAf8BDAH/AQUB/wEFAf8BAwH/AQMB/wEFAf8BBQH/AQoB/wEKAf8BCgH+AQoB
/wEBAe0BAQH/AUABtgFAAf0BYAFmAWAB4AMtAUUDLwFJA2wB6wGAAoUB/gF/A/8BSQP/AR8D/wEMA/8B
BQP/AQMD/wEFA/8BCgP/AQoC/gH/AQEC7QH/AUACtgH9AWACZgHgAy0BRQMvAUkDbAHrAoABhQH+An8C
/wJJAv8CHwL/AgwC/wIFAv8CAwL/AgUC/wIKAv8CCgH+Af8CAQHtAf8CQAG2Af0CYAFmAeADLQFFAwMB
BANWAa4DbgH1A9kB/wPLAf8DtwH/A6cB/wOdAf8DmgH/A5wB/wOfAf8DmwH/A4kB/wNoAfADUgGjAwMB
BAMDAQQDVgGuA24B9QGoAf8BqAH/AYkB/wGJAf8BXAH/AVwB/wE3Af8BNwH/ASIB/wEiAf8BGwH/ARsB
/wEfAf8BHwH/ASYB/wEmAf8BHQH/AR0B/wEFAfMBBQH/AV4BaAFeAfADUgGjAwMBBAMDAQQDVgGuA24B
9QGoA/8BiQP/AVwD/wE3A/8BIgP/ARsD/wEfA/8BJgP/AR0D/wEFAvMB/wFeAmgB8ANSAaMDAwEEAwMB
BANWAa4DbgH1AqgC/wKJAv8CXAL/AjcC/wIiAv8CGwL/Ah8C/wImAv8CHQL/AgUB8wH/Al4BaAHwA1IB
owMDAQQEAAMcAScDXQHHA2MB9gOAAf4D1wH/A8wB/wPCAf8DuwH/A7cB/wOxAf8DgAH+A2gB9ANZAbwD
GwEmCAADHAEnA10BxwNjAfYBgAGFAYAB/gGlAf8BpQH/AYsB/wGLAf8BdAH/AXQB/wFmAf8BZgH/AVwB
/wFcAf8BTgH/AU4B/wFtAYUBbQH+AVMBaAFTAfQBVwFZAVcBvAMbASYIAAMcAScDXQHHA2MB9gGAAoUB
/gGlA/8BiwP/AXQD/wFmA/8BXAP/AU4D/wFtAoUB/gFTAmgB9AFXAlkBvAMbASYIAAMcAScDXQHHA2MB
9gKAAYUB/gKlAv8CiwL/AnQC/wJmAv8CXAL/Ak4C/wJtAYUB/gJTAWgB9AJXAVkBvAMbASYMAAMhATAD
WQG2A2IB7gN9AfoDvgH9A9QB/wPMAf8DvgH9A2oB+QNsAesDVQGsAx8BLBAAAyEBMANZAbYDYgHuA30B
+gGuAb4BrgH9AZ8B/wGfAf8BjAH/AYwB/wFAAb4BQAH9AWgBagFoAfkBYQFsAWEB6wNVAawDHwEsEAAD
IQEwA1kBtgNiAe4DfQH6Aa4CvgH9AZ8D/wGMA/8BQAK+Af0BaAJqAfkBYQJsAesDVQGsAx8BLBAAAyEB
MANZAbYDYgHuA30B+gKuAb4B/QKfAv8CjAL/AkABvgH9AmgBagH5AmEBbAHrA1UBrAMfASwUAAMGAQcD
NgFYA1UBrANmAeUDfgH8A18B+wNlAeIDUwGnAzMBUQMGAQcYAAMGAQcDNgFYA1UBrANmAeUDfgH8AV8B
cwFfAfsDZQHiA1MBpwMzAVEDBgEHGAADBgEHAzYBWANVAawDZgHlA34B/AFfAnMB+wNlAeIDUwGnAzMB
UQMGAQcYAAMGAQcDNgFYA1UBrANmAeUDfgH8Al8BcwH7A2UB4gNTAacDMwFRAwYBBwwAAUIBTQE+BwAB
PgMAASgDAAFAAwABIAMAAQEBAAEBBgABARYAA/+BAAHgAQcB4AEHAeABBwHgAQcBwAEDAcABAwHAAQMB
wAEDAYABAQGAAQEBgAEBAYABAVAAAYABAQGAAQEBgAEBAYABAQHAAQMBwAEDAcABAwHAAQMB4AEHAeAB
BwHgAQcB4AEHCw==
</value>
</data>
<metadata name="ilGames.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
@ -290,8 +311,8 @@
<value>
AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAKCUAAAJNU0Z0AUkBTAIBAQMB
AAEQAQIBEAECASABAAEgAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABgAMAASADAAEBAQABIAYAAUB6
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAJCUAAAJNU0Z0AUkBTAIBAQMB
AAGoAQIBqAECASABAAEgAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABgAMAASADAAEBAQABIAYAAUB6
AANcAecBCAEKAQAB/wMqAUAMAAMqAUADNgFXAz8BbAM/AWwDPwFsAz8BbAM/AWwDPwFsAz8BbAM/AWwD
PwFsAz8BbAM/AWwDPwFsAz8BbAM/AWwDPwFsAz8BbAI7AToBYgMzAVEDGAEhVAADUwGiA1sBwCAAA1QB
pgNZAbzwAAMhATADRgGAFAABFQEfAQQB/wENARUBAAH/AQgBCgEAAf8BCAEKAQAB/wwAA0QBegNTAacC
@ -377,7 +398,7 @@
UgGMAQgB/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEQAf8BUgGMARAB/wFaAZQB
EAH/AVoBlAEQAf8BWgGbARAB/wFaAZwBEAH/AVoBnAEQAf8BWgGcARAB/wFaAZYBFgH/AVoBlAEYAf8B
XQGXARgB/wFjAZwBGAH/AWMBpQEXAf8BYwGlARcB/wFwAbMBIAH/ASsBUAEEAf8IAAMnAToCUwFRAaIB
gwFfASEB+wJlAVwB5wJcAVoBxAJDAUIBdQMxAU0CQAE/AW4CUQFQAZ8CZQFgAeMB/wF4AQAC/wF4AQAB
YQFfASEB+wJlAVwB5wJcAVoBxAJDAUIBdQMxAU0CQAE/AW4CUQFQAZ8CZQFgAeMB/wF4AQAC/wF4AQAB
/wJRAVABnwMSARgcAAMZASIDTgGVAlsBXgHNAlYBVwGyA0QBegMdASkDBgEIBAIEATAAA18B0ANiAe4g
AANhAdQDYwHpvAABSgGEAQYB/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEIAf8B
ZwGpARcB/wFSAYwBCAH/AUoBhAEGAf8BSgGEAQYB/wFSAYwBEAH/AVoBlAEQAf8BWgGXARAB/wFaAZwB
@ -397,152 +418,131 @@
YgHclAABSgGMAQAB/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBCAH/AWcBnQEnAf8BCAEKAQAB
/wEKAQ8BAAH/AUIBdwEDAf8BUgGMARAB/wFaAZwBEAH/ASUBQQEFAf8EAAM6AWABCAEKAQAB/wEIAQoB
AAH/BAADRgGAA0YBgANGAYAcAAMKAQ0DIgExAzQBVANEAXgCUQFQAZ8CYQFdAc8CagFeAe0CZQFdAewC
aAFeAfABgwFfASEB+wH/AXgBAAL/AXgBAAH/AlEBUAGfAxIBGBwAAwYBCAMYASEDMQFNAkwBTQGRAlgB
aAFeAfABYQFfASEB+wH/AXgBAAL/AXgBAAH/AlEBUAGfAxIBGBwAAwYBCAMYASEDMQFNAkwBTQGRAlgB
WgG9Al0BYQHRAlkBXAHDAlEBUwGiAz0BZwIZARoBIwMMAQ8DQAFvA1UBrQNVAa0DVQGtA1UBrQNVAa0D
VQGtA1UBrQNVAa0DVQGtA2gB8AN9AfoDVQGtA1UBrQNVAa0DVQGtA1UBrQNVAa0DVQGtA1UBrQNwAfED
fAH4A1UBrQNVAa0DVQGtA1UBrQNVAa0DVQGtA1UBrQNVAa0DVQGtA0cBgZQAATsBbQECAf8BUgGMAQgB
/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQgB/wFTAY4BEAH/AQ8BGwEAAf8BIwFDAQAB/wFSAYwBEAH/AVIB
jAEQAf8BewG9ATAB/wEIAQoBAAH/AQgBCgEAAf8BCAEKAQAB/wEIAQoBAAH/AQgBCgEAAf8BCAEKAQAB
/wEIAQoBAAH/KAADAwEEAwkBCwMiATEDOAFbAk8BTgGXAl8BXAHIAmYBXwHlAm8BUQH3Ab4BRQFAAf0B
/wF4AQAC/wF4AQAB/wJRAVABnwMSARgcAAQBAwIBAwMVARwDNQFWAksBTAGPAlwBXwHIAl0BYwHfAmAB
ZQHjAlIBUwGlAzQBUwMcAScoAANfAdADYgHuIAADYQHUA2MB6bwAAQgBCgEAAf8BUgGMAQgB/wFSAYwB
CAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBCAH/AU4BggEPAf8BSgGEAQYB/wFSAYwBEAH/AWMBpQEXAf8B
CAEKAQAB/wEIAQoBAAH/ARMBIwEAAf8BQgFzAQYB/wEgAT8BAAH/AQgBCgEAAf8BCAEKAQAB/wEIAQoB
AAH/AQgBCgEAAf8BCAEKAQAB/yAABAEDAwEEAwwBEAMYASADKQE9Az4BagJXAVYBtQJmAV8B5QJvAVEB
9wH/AXgBAAL/AXgBAAH/AlEBUAGfAxIBGCAABAEDBwEJAxQBGwMqAUADQwF2A1UBrwJaAWMB6QJbAV8B
0AJQAVEBnwMzAVEoAANfAdADYgHuIAADYQHUA2MB6cAAAUIBcwEGAf8BUgGMAQgB/wFSAYwBCAH/AVIB
jAEIAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEQAf8BUgGMARAB/wFKAYQBBgH/ARABHgEAAf8BMQFaAQAB
/wFNAYQBDQH/AVoBnAEQAf8BWgGcARAB/wFSAYwBCAH/ARABHgEAAf8BCAEKAQAB/wEIAQoBAAH/A0YB
gCwAAwIBAwMLAQ4DIAEuA0MBdgJXAVUBsQJmAWAB4AJjAUgB9gFtAWoBQQH5AlEBUAGcAxIBFwwABAED
DAEQAxcBHwMdASgDHQEoAwwBDwgAAw8BFAImAScBOQJHAUgBgwNiAeECXAFlAecDXgHSAj8BQAFuKAAD
XwHQA2IB7iAAA2EB1ANjAenEAAFJAYkBAAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEIAf8B
UgGMARAB/wFSAYwBEAH/AVIBjAEQAf8BUgGMARAB/wFaAZQBEAH/AVoBnAEQAf8BWgGcARAB/wFaAZwB
EAH/AVoBnAEQAf8BWgGUARgB/wFCAXMBBgH/AQoBDgEAAf8wAAQBAwMBBAMMAQ8DHgEqAzoBYQJZAVcB
uQJjAVsB5ANiAe4CTwFOAZcDEgEXDAADAgEDAyEBLwM2AVkCQgFDAXUCQQFCAXMDHgErCAADBAEFAwwB
DwM4AVwCXQFgAc4CXQFlAewCWQFnAe8DRgF/KAADXwHQA2IB7iAAA2EB1ANjAenIAAE6AWsBAAH/AVIB
jAEIAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEQAf8BUgGMARAB/wFaAZQBEAH/AVoBlAEQAf8BWgGcARAB
/wFaAZwBEAH/AVoBnAEQAf8BWgGcARAB/wFaAZQBGAH/AVoBlAEYAf8BYwGlARcB/wEZASwBAwH/OAAD
AgEDAwgBCgMgAS0CQQFAAXECTQFMAZEDUAGaAjsBOgFiAwwBDwwAAwMBBAMrAUEDRAF6A1MBpwNVAa0D
NwFaAxgBIAMJAQsDBgEHAw0BEQM5AV8CXQFhAdECWQFnAe8CYAFvAfMCRgFHAYEoAANfAdADYgHuIAAD
YQHUA2MB6cwAASwBVQEAAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEQAf8BUgGMARAB/wFaAZQBEAH/AVoB
lAEQAf8BWgGcARAB/wFaAZwBEAH/AVoBnAEQAf8BWgGcARAB/wFaAZQBGAH/AVoBlAEYAf8BIQFBAQAB
/0AABAIDBwEJAxAEFQEcAhYBFQEdAw8BEwMCAQMMAAMDAQQDMANLAUwBjwJbAV0BygJbAWEB3gNOAZQD
NAFTAxUBHAMNAREDHgErAkMBRAF3Al0BYwHfAmUBcAHxAloBYwHpA0QBeygAA18B0ANiAe4gAANhAdQD
YwHpyAABEgEiAQAB/wFMAYYBBgH/AVIBjAEIAf8BWgGcARAB/wFQAYoBCAH/AVIBjAEQAf8BWgGUARAB
/wFaAZwBEAH/AVoBnAEQAf8BWgGcARAB/wFaAZwBEAH/AVoBnAERAf8BaQGrAR8B/wEIAQoBAAH/bAAD
AgEDAyEBLwM6AWEDVQGtAl8BYwHaA1oBvwJQAVEBnwNEAXoCQQFCAXIDSQGFAlYBVwGyAl4BagHtAmAB
ZAHbAlUBVwGxAzgBWygAA18B0ANiAe4gAANhAdQDYwHpyAABEAEeAQAB/wFIAX0BBwH/AVkBkwETAf8B
VQGIARgB/wgAASEBQQEAAf8BQgF7AQAB/wFSAYwBCAH/AVUBkQEIAf8BOQFmAQQB/wNZAe94AAMGAQgD
FwEfA0QBewJZAVwBxgJbAWMB5AJTAWgB9ANiAe4DYgHuAmUBcAHxAkgBYwH2AisBfgH8AlkBXAG+Az4B
awMkATQoAANfAdADYgHuIAADYQHUA2MB6dAAAR4BOgEAAf+cAAQCAwkBDAMqAz8BQAFuA04BlgJWAVgB
swJZAVwBwQJaAV0BxwJaAV0BxwJXAVkBuQJRAVIBpAJAAUEBcQMlATYDEwEZKAADXwHQA2IB7iAAA2EB
1ANjAen/AHkABAEDCwEOAyYBOAM5AV4DRgF9AkoBSwGLA0oBiQM+AWsDKgE/AxcBHwMCAQMsAANTAaID
WgG/IAADVAGmA1kBu6gAAUIBTQE+BwABPgMAASgDAAGAAwABIAMAAQEBAAEBBgABAhYAA/8BAAP/AccC
AAEHAv8BzwHzAf8EAAL/Ac8BhwIAAQcC/wHPAfMB/wQAAf8B/gEAAQcCAAEHAv8BzwHzAf8EAAH/AfwB
AAEHAgABBwL/Ac8B8wH/BAAB/wH4AQABDwIAAQcC/wHPAfMB/wQAAf8B8AEAAQcCAAEHAv8BzwHzAf8E
AAH/AeABAAEDAgABBwL/Ac8B8wH/BAAB/wHAAQABAQH8AQMD/wHPAfMB/wQAAf8BwAEAAQEB/AEDA/8B
zwHzAf8EAAH/AeACAAH8AQMB4AEfCAAB/wH8ASABAAH8AQMB4AEfCAAB/wH+AeABAAH8AQMB4AEfCAAB
/wHAAgAB/AEDAeABHwH/Ac8B8wH/BAAB/wGAAgAB/AEDAeABHwH/Ac8B8wH/BAAB/wMAAfwBAwHgAR8B
/wHPAfMB/wQAAf4CAAEBAQABAwHgAR8B/wHPAfMB/wQAAfwCAAEBAQABAwH4AR8B/wHPAfMB/wQAAfgC
AAEBAQABAwH4AR8B/wHPAfMB/wQAAfgCAAEDAQABAwH4AQMB/wHPAfMB/wQAAfgCAAEHAQABAwH4AQMI
AAH4AgABDwEAAQMB+AkAAfgBAAFEAX8BAAEDAfgJAAH4AQABAQH/AYABAwH4AQAB/wHPAfMB/wQAAfgC
AAF/AYABAwH8AQAB/wHPAfMB/wQAAfwCAAF/AfABAwGBAYAB/wHPAfMB/wQAAf4CAAH/AfABAwGBAYAB
/wHPAfMB/wQAAf8CAAH/AfwBAwGAAQAB/wHPAfMB/wQAAf8BgAEBAf8B/gEDAYABAAH/Ac8B8wH/BAAB
/wEAAQMD/wGAAQAB/wHPAfMB/wQAAf8BDAEPA/8BwAEAAf8BzwHzAf8EAAH/Ad8E/wHAAQAB/wHPAfMB
/wQABv8B8AEBAf8BzwHzAf8EAAs=
/wEIAQoBAAH/KAADAwEEAwkBCwMiATEDOAFbAk8BTgGXAl8BXAHIAmYBXwHlAm8BUQH3Ab4CQAH9Af8B
eAEAAv8BeAEAAf8CUQFQAZ8DEgEYHAAEAQMCAQMDFQEcAzUBVgJLAUwBjwJcAV8ByAJdAWMB3wJgAWUB
4wJSAVMBpQM0AVMDHAEnKAADXwHQA2IB7iAAA2EB1ANjAem8AAEIAQoBAAH/AVIBjAEIAf8BUgGMAQgB
/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQgB/wFOAYIBDwH/AUoBhAEGAf8BUgGMARAB/wFjAaUBFwH/AQgB
CgEAAf8BCAEKAQAB/wETASMBAAH/AUIBcwEGAf8BIAE/AQAB/wEIAQoBAAH/AQgBCgEAAf8BCAEKAQAB
/wEIAQoBAAH/AQgBCgEAAf8gAAQBAwMBBAMMARADGAEgAykBPQM+AWoCVwFWAbUCZgFfAeUCbwFRAfcB
/wF4AQAC/wF4AQAB/wJRAVABnwMSARggAAQBAwcBCQMUARsDKgFAA0MBdgNVAa8CWgFjAekCWwFfAdAC
UAFRAZ8DMwFRKAADXwHQA2IB7iAAA2EB1ANjAenAAAFCAXMBBgH/AVIBjAEIAf8BUgGMAQgB/wFSAYwB
CAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBEAH/AVIBjAEQAf8BSgGEAQYB/wEQAR4BAAH/ATEBWgEAAf8B
TQGEAQ0B/wFaAZwBEAH/AVoBnAEQAf8BUgGMAQgB/wEQAR4BAAH/AQgBCgEAAf8BCAEKAQAB/wNGAYAs
AAMCAQMDCwEOAyABLgNDAXYCVwFVAbECZgFgAeACYwFIAfYCagFBAfkCUQFQAZwDEgEXDAAEAQMMARAD
FwEfAx0BKAMdASgDDAEPCAADDwEUAiYBJwE5AkcBSAGDA2IB4QJcAWUB5wNeAdICPwFAAW4oAANfAdAD
YgHuIAADYQHUA2MB6cQAAUkBiQEAAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwB
EAH/AVIBjAEQAf8BUgGMARAB/wFSAYwBEAH/AVoBlAEQAf8BWgGcARAB/wFaAZwBEAH/AVoBnAEQAf8B
WgGcARAB/wFaAZQBGAH/AUIBcwEGAf8BCgEOAQAB/zAABAEDAwEEAwwBDwMeASoDOgFhAlkBVwG5AmMB
WwHkA2IB7gJPAU4BlwMSARcMAAMCAQMDIQEvAzYBWQJCAUMBdQJBAUIBcwMeASsIAAMEAQUDDAEPAzgB
XAJdAWABzgJdAWUB7AJZAWcB7wNGAX8oAANfAdADYgHuIAADYQHUA2MB6cgAAToBawEAAf8BUgGMAQgB
/wFSAYwBCAH/AVIBjAEIAf8BUgGMARAB/wFSAYwBEAH/AVoBlAEQAf8BWgGUARAB/wFaAZwBEAH/AVoB
nAEQAf8BWgGcARAB/wFaAZwBEAH/AVoBlAEYAf8BWgGUARgB/wFjAaUBFwH/ARkBLAEDAf84AAMCAQMD
CAEKAyABLQJBAUABcQJNAUwBkQNQAZoCOwE6AWIDDAEPDAADAwEEAysBQQNEAXoDUwGnA1UBrQM3AVoD
GAEgAwkBCwMGAQcDDQERAzkBXwJdAWEB0QJZAWcB7wJgAW8B8wJGAUcBgSgAA18B0ANiAe4gAANhAdQD
YwHpzAABLAFVAQAB/wFSAYwBCAH/AVIBjAEIAf8BUgGMARAB/wFSAYwBEAH/AVoBlAEQAf8BWgGUARAB
/wFaAZwBEAH/AVoBnAEQAf8BWgGcARAB/wFaAZwBEAH/AVoBlAEYAf8BWgGUARgB/wEhAUEBAAH/QAAE
AgMHAQkDEAQVARwCFgEVAR0DDwETAwIBAwwAAwMBBAMwA0sBTAGPAlsBXQHKAlsBYQHeA04BlAM0AVMD
FQEcAw0BEQMeASsCQwFEAXcCXQFjAd8CZQFwAfECWgFjAekDRAF7KAADXwHQA2IB7iAAA2EB1ANjAenI
AAESASIBAAH/AUwBhgEGAf8BUgGMAQgB/wFaAZwBEAH/AVABigEIAf8BUgGMARAB/wFaAZQBEAH/AVoB
nAEQAf8BWgGcARAB/wFaAZwBEAH/AVoBnAEQAf8BWgGcAREB/wFpAasBHwH/AQgBCgEAAf9sAAMCAQMD
IQEvAzoBYQNVAa0CXwFjAdoDWgG/AlABUQGfA0QBegJBAUIBcgNJAYUCVgFXAbICXgFqAe0CYAFkAdsC
VQFXAbEDOAFbKAADXwHQA2IB7iAAA2EB1ANjAenIAAEQAR4BAAH/AUgBfQEHAf8BWQGTARMB/wFVAYgB
GAH/CAABIQFBAQAB/wFCAXsBAAH/AVIBjAEIAf8BVQGRAQgB/wE5AWYBBAH/A1kB73gAAwYBCAMXAR8D
RAF7AlkBXAHGAlsBYwHkAlMBaAH0A2IB7gNiAe4CZQFwAfECSAFjAfYCKwF+AfwCWQFcAb4DPgFrAyQB
NCgAA18B0ANiAe4gAANhAdQDYwHp0AABHgE6AQAB/5wABAIDCQEMAyoDPwFAAW4DTgGWAlYBWAGzAlkB
XAHBAloBXQHHAloBXQHHAlcBWQG5AlEBUgGkAkABQQFxAyUBNgMTARkoAANfAdADYgHuIAADYQHUA2MB
6f8AeQAEAQMLAQ4DJgE4AzkBXgNGAX0CSgFLAYsDSgGJAz4BawMqAT8DFwEfAwIBAywAA1MBogNaAb8g
AANUAaYDWQG7qAABQgFNAT4HAAE+AwABKAMAAYADAAEgAwABAQEAAQEGAAECFgAD/wEAA/8BxwIAAQcC
/wHPAfMB/wQAAv8BzwGHAgABBwL/Ac8B8wH/BAAB/wH+AQABBwIAAQcC/wHPAfMB/wQAAf8B/AEAAQcC
AAEHAv8BzwHzAf8EAAH/AfgBAAEPAgABBwL/Ac8B8wH/BAAB/wHwAQABBwIAAQcC/wHPAfMB/wQAAf8B
4AEAAQMCAAEHAv8BzwHzAf8EAAH/AcABAAEBAfwBAwP/Ac8B8wH/BAAB/wHAAQABAQH8AQMD/wHPAfMB
/wQAAf8B4AIAAfwBAwHgAR8IAAH/AfwBIAEAAfwBAwHgAR8IAAH/Af4B4AEAAfwBAwHgAR8IAAH/AcAC
AAH8AQMB4AEfAf8BzwHzAf8EAAH/AYACAAH8AQMB4AEfAf8BzwHzAf8EAAH/AwAB/AEDAeABHwH/Ac8B
8wH/BAAB/gIAAQEBAAEDAeABHwH/Ac8B8wH/BAAB/AIAAQEBAAEDAfgBHwH/Ac8B8wH/BAAB+AIAAQEB
AAEDAfgBHwH/Ac8B8wH/BAAB+AIAAQMBAAEDAfgBAwH/Ac8B8wH/BAAB+AIAAQcBAAEDAfgBAwgAAfgC
AAEPAQABAwH4CQAB+AEAAUQBfwEAAQMB+AkAAfgBAAEBAf8BgAEDAfgBAAH/Ac8B8wH/BAAB+AIAAX8B
gAEDAfwBAAH/Ac8B8wH/BAAB/AIAAX8B8AEDAYEBgAH/Ac8B8wH/BAAB/gIAAf8B8AEDAYEBgAH/Ac8B
8wH/BAAB/wIAAf8B/AEDAYABAAH/Ac8B8wH/BAAB/wGAAQEB/wH+AQMBgAEAAf8BzwHzAf8EAAH/AQAB
AwP/AYABAAH/Ac8B8wH/BAAB/wEMAQ8D/wHAAQAB/wHPAfMB/wQAAf8B3wT/AcABAAH/Ac8B8wH/BAAG
/wHwAQEB/wHPAfMB/wQACw==
</value>
</data>
<metadata name="ilStoreThumbnails.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>12, 128</value>
</metadata>
<metadata name="ilTabIcons.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>20, 44</value>
<metadata name="ilProfilePics.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<data name="ilTabIcons.ImageStream" mimetype="application/x-microsoft.net.object.binary.base64">
<data name="ilProfilePics.ImageStream" mimetype="application/x-microsoft.net.object.binary.base64">
<value>
AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAshIAAAJNU0Z0AUkBTAIBAQQB
AAEQAQMBEAEDARABAAEQAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABQAMAASADAAEBAQABIAYAASD/
AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/ACIAA2cB7wJnAVkB7wFnAV0BWQHvAWcBWwFZAe8B
ZwFbAVkB7wFnAlkB7wFnAWQBWQHvA2cB7wNnAe8DZwHvA2cB7wNnAe8DZwHvA2cB7wNnAe8DZwHvAwcB
CQMqAT8DRQF8A1kBuwNjAd8DaAH0A4AB/gOBAf8DgQH/A4EB/wOAAf4DaAH0A2MB3wNaAboDRAF6AycB
OjgAAzMBUQNuAfUIAAM3AVoDWAG4A2MB3wJjAV0B3wFiAl0B3wNdAd8DXQHfAWECXQHfA2MB3wNjAd8D
VQGsAzABSwgAA/gB/wG5AZUBPAH/AYMBfQFuAf8BhAF9AWwB/wGqAYQBJwH/AawBewEAAf8BzAG8AZQB
/wN+Af8DfgH/A34B/wN+Af8DfgH/A34B/wN+Af8DfgH/A44B/wNDAXUDXQHMA3wB+AOBAf8DgQH/A4EB
/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A3wB+ANUAag4AAMSARgDPwFtBAADOwFiA10B
xQNoAfQBnwFlATEB/wGXAVMBFwH/AZYBSwEJAf8BkwFGAQEB/wGMAUMBAwH/AX0BQAELAf8BawFAARoB
/wFuAVABNgH/A2gB8ANaAbcDNAFUBAAE/wGXAYsBbQH/AoEBgAH/AYIBgQGAAf8BmAGIAWAB/wHKAZAB
AAH/Ad0BzAGfAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOTAf8DagHtA30B+gOBAf8D
gQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DVQGvNAADXwHTAz0B
ZwQAAzUBVQNdAccCbgFaAfUBuAFlARsB/wG5AVgBAgH/AckBXwEAAf8B2AFlAQAB/wHcAWcBAAH/AdYB
ZAEAAf8BwwFcAQAB/wGiAUwBAAH/AXwBOwEDAf8BbgFGASMB/wNoAfADWgG3AzABSgT/AYYBhAF9Af8D
gQH/A4EB/wGHAYMBegH/Ac8BlAEAAf8B3gHMAZ8B/wPgAf8D4AH/A+AB/wPgAf8D4AH/A+AB/wPgAf8D
4AH/A7wB/wNjAd8DbgH1A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8D
gQH/A4EB/wNVAa80AANaAcIDNAFTBAADXAHEAnwBXAH4AdQBcQEYAf8B1wFlAQAB/wHlAWwBAAH/AfIB
cgEAAf8B+gF1AQAB/wH8AXYBAAH/AfoBdgEAAf8B8wFyAQAB/wHiAWsBAAH/Ab0BWQEAAf8BhwFAAQAB
/wFxAUgBIwH/A2gB8ANWAasE/wGLAYYBegH/A4EB/wOBAf8BjgGGAXEB/wHPAZQBAAH/Ad4BzAGfIf8D
ygH/AzYBWANbAcADbgH1A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8D
aAH0A1IBpBAAAw0BEQM/AWwDUwGnAVwCWQG+AVgCVgGzAUgCRwGDAyEBMAQAA28B8wM6AWAIAAH+Ad0B
wQH/Ae0BgAEgAf8B7QFxAQIB/wHzAXMBAAH/AfoBdgEAAf8B/gF4AQAC/wF7AQgC/wGIAScC/wGiAVMB
/wH+AYEBFwH/AfwBeAEEAf8B7AFvAQAB/wHBAVsBAAH/AYYBQQEDAf8BeAFWATYB/wNjAd8E/wGsAZYB
YAH/AYMBggF/Af8BhQGCAX0B/wGzAZMBRAH/Ac8BlAEAAf8B3gHMAZ8B/wOwAf8DsAH/A7AB/wOwAf8D
sAH/A7AB/wOwAf8DsAH/A6gB/wMCAQMDGgEjAzgBXANUAagDYgHXA3AB8QOAAf4DgQH/A4EB/wOBAf8D
gQH9A2gB8ANhAdQDUwGlAzYBWQMYASAIAAMaASQDUgGgAmMBSAH2AaIBcwEAAf8BrgF8AQAB/wGwAX0B
AAH/AagBeAEAAf8BlQFqAQAB/wKAAWIB/gFcAlkBxgNXAbUDFgEeCAAB/wGyAW8B/wH9AYABEQH/AfwB
dwEBAf8B/QF3AQAC/wF4AQAC/wF/AQ8C/wGSATsC/wGzAYMC/wHqAeAC/wGQAT0C/wF7AQoB/wH8AXcB
AAH/AeUBbAEAAf8BsQFUAQAB/wGEAUsBGgH/A2MB3wT/AdkBqgE3Af8BvgGYATgB/wHAAZgBNgH/AdwB
ogEUAf8BzwGUAQAB/wHeAcwBnwH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DkwH/RAAD
IAEtAmMBWgHpAb8BiAEAAf8BzQGVAQoB/wGwAYgBJwH/AXMBZAE/Af8BTQFLAUcB/wFOAUsBQgH/AWYB
VwExAf8BmgF0ARcB/wGkAXYBAwH/AXABTwEAAf8DQwF2BAEEAAH/AZoBQgL/AYMBFQH/Af4BegEEAv8B
eAEAAv8BeAEAAv8BlQE/Av8BygGuAv8B2gHGAv8B7QHlAv8BlgFJAv8BfAENAf8B/gF4AQAB/wH0AXMB
AAH/AdABYgEAAf8BmgFOAQoB/wFjAl0B3wT/AeEBrgExAf8BvQGXATsB/wHAAZgBNQH/AeMBpQEKAf8B
zwGUAQAB/wHeAcwBnwH/A8AB/wPAAf8DwAH/A8AB/wPAAf8DwAH/A8AB/wPAAf8DrwH/CAADAgEDAwgB
CgMhAS8DMQFOAz0BaANDAXYDRAF6A0MBdQM9AWcDMQFNAyABLgMHAQkEAggAAmMBWgHpAdkBmgEAAf8B
2gGjARwB/wKOAYwB/wOKAf8DlwH/A5sB/wORAf8DdAH/A0gB/wFDAUIBPwH/AbUBgwEHAf8BegFXAQAB
/wM2AVgEAAH/AZUBNwL/AYkBHwL/AX0BCAL/AXgBAAL/AXgBAAL/AagBXAL/AeABzQL/AaEBZgL/AdgB
xQL/AbkBlAL/AYcBIwL/AXgBAAH/AfsBdgEAAf8B4gFqAQAB/wGvAVQBAwH/AWMCXQHfBP8BuwGdAVMB
/wGIAYQBeQH/AYwBhQF0Af8BxAGZATAB/wHPAZQBAAH/Ad4BzAGfIf8DygH/BAADEwEaAzkBXQNZAbwD
ZAHbA2oB7QNjAfYDXwH7A4EB/QNfAfsDYwH2A2UB7ANjAdoDWgG6AzgBXAMTARoDQwF2AekBpwECAf8B
6QGrARIB/wHQAcoBuwH/A6wB/wNdAf8DTAH/A0sB/wNEAf8DDwH/A7MB/wNmAf8BVAFMAToB/wGuAX0B
BAH/A10BzAQAAf8BoAFJAv8BkgExAv8BgQERAv8BeQEDAv8BeAEAAv8BqAFcAv8B4AHNAv8BoQFmAv8B
2AHFAv8BwAGfAv8BiQEnAv8BeAEAAf8B/gF4AQAB/wHsAW8BAAH/Ab8BWgECAf8BYwJdAd8E/wGUAYoB
cwH/A4EB/wOBAf8BmgGKAWMB/wHPAZQBAAH/Ad4BzAGfAf8D0AH/A9AB/wPQAf8D0AH/A9AB/wPQAf8D
0AH/A9AB/wO1Af8DGgEkA1YBrgNoAfQDgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8D
gQH/A4EB/wNrAfIDUgGhAmoBYQHmAe0BrQEQAf8B9AHQAXYB/wP6Af8D+gH/A30B/wN/Af8DgAH/A4AB
/wN+Af8DhAH/A7sB/wNqAf8BqAGAARwB/wJjAUgB9gQAAf8BswFvAv8BngFIAv8BiAEeAv8BfAEHAv8B
eAEAAv8BmAFDAv8BzgG0Av8B1wHAAv8B6gHgAv8BnQFXAv8BfgERAv8BeAEAAv8BeAEAAf8B8AFxAQAB
/wHLAWQBCQH/AWMBYQFdAd8E/wGGAYMBfgH/A4EB/wOBAf8BhgGDAXsB/wHPAZQBAAH/Ad4BzAGfAf8D
gQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOTAf8DVwGyA2UB5wOBAf8DgQH/A4EB/wOBAf8D
gQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DVQGvA2IB7gHvAbQBIQH/AfcB3AGXCf8D
kQH/A4gB/wOHAf8DhwH/A4EB/wNXAf8D5gH/A6MB/wG2AZEBNgH/AmoBQQH5BAAB/wHMAZ8C/wGsAWMC
/wGTATMC/wGBAREC/wF5AQIC/wGCARYC/wGaAUsC/wGuAXgC/wGlAVcC/wGBARcC/wF5AQQC/wF4AQAC
/wF4AQAB/wHwAXEBAAH/AdUBcQEXAf8CYwFdAd8E/wGLAYYBeQH/A4EB/wOBAf8BjgGGAXEB/wHPAZQB
AAH/Ad4BzAGfAf8DoQH/A6EB/wOhAf8DoQH/A6EB/wOhAf8DoQH/A6EB/wOhAf8DbwHzA18B+wOBAf8D
gQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DVQGvA0sBjQHwAb4B
PwH/AfQBzQFsIf8D+wH/A9AB/wHXAacBMQH/AmEBXQHRBAAB/wHpAdUC/wG8AYEC/wGkAVQC/wGOASoC
/wF/AQ0C/wF5AQIC/wF7AQkC/wGCAR0C/wF4AQAC/wF4AQAC/wF4AQEC/wF6AQQC/wF6AQMB/wHzAXQB
AwH/AeIBhAEyAf8DYwHfBP8BpwGUAWcB/wGDAYIBfwH/AYUBgwF+Af8BsAGUAU4B/wHTAZcBAgH/AeAB
zgGfAf8D5wH/A+cB/wPnAf8D5wH/A+cB/wPnAf8D5wH/A+cB/wPAAf8DZAHbA2gB9AOBAf8DgQH/A4EB
/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DVQGvAwcBCQNiAe4B8QG8ATsB
/wH6AeoBwgH/A9wB/wN3Af8DaAH/A2gB/wNoAf8DMgn/AfIB3QGpAf8B6gGpAQgB/wM+AWoEAANeAdID
agH5Af8BuwF9Av8BowFSAv8BkAEsAv8BggETAv8BfQEIAv8BegEEAv8BeQECAv8BegEEAv8BfQEJAv8B
gAEPAv8BfwENAf8B+AGGASAB/wNoAfQDWAG4BP8B1wGxAVIB/wGaAY8BdAH/AaABkgFtAf8B4AGvATcB
/wHnAakBEAH/AesB1QGgAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOTAf8DPAFkA18B
yQN9AfoDgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wN9AfoDVQGqBAAD
MwFRA2gB8AHzAcYBWAH/AfoB5wG4Fv8B/gH7Af8B+QHiAaoB/wHvAbgBLQH/A04BlgQCBAADPAFmA2MB
1QN8AfgB/wG+AYUC/wGqAV8C/wGZAT4C/wGNAScC/wGGARoC/wGDARUC/wGFARkC/wGKASIC/wGNASgC
/wGTATMB/wJuAWgB9QNdAcUDNgFZBP8B9AHNAWwB/wH0AcsBZgH/AfQBywFlAf8B9AHLAWUB/wHxAcEB
SQH/AfkB4wGsAf8DiQH/A4kB/wOJAf8DiQH/A4kB/wOJAf8DiQH/A4kB/wOaAf8DBgEIAzEBTANQAZsD
ZQHsA30B+gOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DfQH6A2oB7QNQAZsDLwFJCAADIgExA18B
yQJ9AWcB+gHzAcoBZQH/AfkB4QGmAf8B+wHtAcwB/wH7AewByAH/AfgB3QGbAf8DgAH+AmUBXgHiAz0B
aAQBDAADQgFyA2MB1QNqAfkB/wHJAZkC/wG8AX8C/wGuAWYC/wGkAVMC/wGfAUoC/wGfAUsC/wGjAVEC
/wGnAVgB/wN8AfgDXQHHAzsBYgQAQP8IAAMFAQYDEgEXAzoBYANRAZ8DXwHTA2cB7wNjAfYDYgHuA14B
0gNRAZ4DOQFfAxEBFgMFAQYUAAMPARMDRwGCA2QB2wJ+AW8B/ANnAeoDVAGoAygBOxwAAzwBZQNeAdIB
/wHvAeAC/wHcAbwC/wHNAZ8C/wHBAYoC/wG7AX8C/wG/AYYC/wHNAaEC/wHpAdYB/wNcAcQDNQFVCAAB
QgFNAT4HAAE+AwABKAMAAUADAAEgAwABAQEAAQEGAAEBFgAD/4UAAf8B/AHAAQMEAAH/AfwBgAEBBAAB
/wH5BgAB/wH5BgAB8AETBgABwAEDBAAC/wGAAQEEAAHAAQEBgAEBBAABgAIAAQEHAAEBBwABAQcAAQEH
AAEBBgABgAEBBgABwAEDAYABAQIAAcABAQHwAR8BwAEDCw==
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAA0A0AAAJNU0Z0AUkBTAMBAQAB
MAECATABAgEgAQABIAEABP8BIQEACP8BQgFNATYHAAE2AwABKAMAAYADAAEgAwABAQEAASAGAAFAEgAD
rQH/A7oB/wO6Af8DuQH/A7oB/wO6Af8D2gX/A/wB/wP+Df8D/QH/A/wR/wP8Af8D/g3/A/0B/wPZAf8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af//AIEAA58B/wO6Af8DugH/A7oB/wO6Af8DugH/A9oJ/wP9Af8D
/g3/A/0B/wP9Ef8D/AH/A/4N/wPaAf8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af//AIEAA6IB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A9oN/wP8Af8D/iX/A/wN/wPaAf8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af//
AIEAA6UB/wO6Af8DugH/A7oB/wO6Af8DugH/A9kR/wP+Ff8D/R3/A9oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB//8AgQADpAH/A7kB/wO6Af8DugH/A7oB/wO6Af8D2QH/A/wV/wP+Df8D/QH/A/0R/wP+Af8D
/gH/A9oB/wO6Af8DugH/A7kB/wO6Af8DugH/A7oB//8AgQADoQH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
2gH/A/4B/wP9Ef8D/AH/A/4N/wP9Af8D/RH/A/wB/wPZAf8DugH/A7oB/wO6Af8DuQH/A7oB/wO6Af//
AIEAA58B/wO6Af8DugH/A7oB/wO6Af8DugH/A9oF/wP9Af8D/RH/A/0B/wP+Df8D/QH/A/0R/wPZAf8D
ugH/A7oB/wO6Af8DugH/A7kB/wO6Af//AIEAA7EB/wO6Af8DugH/A7oB/wO6Af8DugH/A9MJ/wP+Ff8D
/AH/A/4h/wPTAf8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af//AIEAA7oB/wO6Af8DugH/A7oB/wO6Af8D
uQH/A8AB/wP9Df8D/hH/A/4V/wP9Bf8D/QH/A8AB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQAD
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A9oN/wP+Af8D/RX/A/4N/wP9Af8D/AH/A9oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af//AIEAA7oB/wO5Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
3Q3/A/0B/wP9Ef8D/QH/A/4N/wPcAf8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQAD
ugH/A7oB/wO5Af8DuQH/A7oB/wO6Af8DugH/A7oB/wO5Af8DyQH/A+wB/wP+Bf8D/gH/A/wR/wP9Af8D
/QH/A+wB/wPKAf8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af//AIEAA7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7kB/wO6Af8DwQH/A9IB/wPfAf8D5gH/A+oB/wPrAf8D
5wH/A98B/wPSAf8DwAH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af//
AIEAA7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
vQH/A8cB/wPGAf8DvQH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af//AIEAA7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A8IB/wPnAf8D/QX/A/4B/wP6Af8D5gH/A8IB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB//8AgQADugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wPIAf8D+QH/A/0N/wP9Af8D/QH/A/oB/wPIAf8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO5Af8DugH/A7oB//8AgQADugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A74B/wP4Bf8D/AH/A/4N/wP9Af8D/AH/A/gB/wO+Af8DugH/A7oB/wO6Af8DuQH/A7oB/wO6Af8D
ugH/A7oB/wO5Af8DugH//wCBAAO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7kB/wO6Af8D
2w3/A/0B/wP9Df8D/QH/A/4B/wPbAf8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH//wCBAAO6Af8DugH/A7oB/wO6Af8DugH/A7kB/wO6Af8DugH/A7oB/wO6Af8D8BH/A/wB/wP+Ef8D
8AH/A7oB/wO6Af8DugH/A7oB/wO5Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQADugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A/gB/wP9Jf8D+AH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB//8AgQADugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A/QB/wP9Af8D/BH/A/4B/wP+Cf8D9QH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB//8AgQADugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A+UF/wP+Af8D
/BH/A/wB/wP9Bf8D5QH/A7oB/wO5Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQAD
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DuQH/A8gB/wP+Bf8D/gH/A/wR/wP9Af8D
/QH/A8gB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7kB/wO6Af//AIEAA7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D3Qn/A/4V/wPcAf8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQADugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D2QH/A/wJ/wP+Bf8D/AH/A9kB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQADugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A8AB/wPWAf8D4gH/A+EB/wPVAf8DwAH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQADugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7kB/wO6Af8DugH/A7oB/wO6Af8DugH/A7kB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQAD
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO5Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO5Af8D
uQH/A7oB//8AgQADugH/A7oB/wO6Af8DuQH/A7oB/wO6Af8DugH/A7oB/wO5Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO5Af8D
ugH/A7oB/wO6Af8DugH/A7oB//8AgQADugH/A7oB/wO6Af8DugH/A7kB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DuQH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQADugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQADugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8D
ugH/A7oB/wO6Af8DugH/A7kB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB/wO6Af8DugH/A7oB//8AgQAB
QgFNAT4HAAE+AwABKAMAAYADAAEgAwABAQEAAQEGAAECFgAD//8A/wADAAs=
</value>
</data>
<metadata name="ctxmChangeStatus.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">

View File

@ -37,13 +37,11 @@
btnDecline = new Button();
btnCancelRequest = new Button();
btnMessage = new Button();
pbUserStatus = new PictureBox();
pbCurrencyIcon = new PictureBox();
lblCurrencyAmount = new Label();
flpUsernameCurrency = new FlowLayoutPanel();
pCurrency = new Panel();
((System.ComponentModel.ISupportInitialize)pbUserPfp).BeginInit();
((System.ComponentModel.ISupportInitialize)pbUserStatus).BeginInit();
((System.ComponentModel.ISupportInitialize)pbCurrencyIcon).BeginInit();
flpUsernameCurrency.SuspendLayout();
pCurrency.SuspendLayout();
@ -52,9 +50,9 @@
// pbUserPfp
//
pbUserPfp.Image = Properties.Resources.DefaultPfp;
pbUserPfp.Location = new Point(13, 11);
pbUserPfp.Location = new Point(9, 5);
pbUserPfp.Name = "pbUserPfp";
pbUserPfp.Size = new Size(128, 128);
pbUserPfp.Size = new Size(139, 138);
pbUserPfp.SizeMode = PictureBoxSizeMode.StretchImage;
pbUserPfp.TabIndex = 2;
pbUserPfp.TabStop = false;
@ -148,17 +146,6 @@
btnMessage.Visible = false;
btnMessage.Click += btnMessage_Click;
//
// pbUserStatus
//
pbUserStatus.BackColor = Color.Transparent;
pbUserStatus.Image = Properties.Resources.OfflineIcon;
pbUserStatus.Location = new Point(115, 1);
pbUserStatus.Name = "pbUserStatus";
pbUserStatus.Size = new Size(32, 32);
pbUserStatus.SizeMode = PictureBoxSizeMode.StretchImage;
pbUserStatus.TabIndex = 10;
pbUserStatus.TabStop = false;
//
// pbCurrencyIcon
//
pbCurrencyIcon.Image = Properties.Resources.CurrencyIcon;
@ -213,7 +200,6 @@
Controls.Add(btnAccept);
Controls.Add(btnDecline);
Controls.Add(btnCancelRequest);
Controls.Add(pbUserStatus);
Controls.Add(btnAddContact);
Controls.Add(rtxtBio);
Controls.Add(pbUserPfp);
@ -230,7 +216,6 @@
FormClosed += Profile_FormClosed;
Load += frmProfile_Load;
((System.ComponentModel.ISupportInitialize)pbUserPfp).EndInit();
((System.ComponentModel.ISupportInitialize)pbUserStatus).EndInit();
((System.ComponentModel.ISupportInitialize)pbCurrencyIcon).EndInit();
flpUsernameCurrency.ResumeLayout(false);
flpUsernameCurrency.PerformLayout();
@ -249,7 +234,6 @@
private Button btnDecline;
private Button btnCancelRequest;
private Button btnMessage;
private PictureBox pbUserStatus;
private PictureBox pbCurrencyIcon;
private Label lblCurrencyAmount;
private FlowLayoutPanel flpUsernameCurrency;

View File

@ -1,41 +1,46 @@
using QtCNETAPI.Dtos.User;
using QtCNETAPI.Services.ApiService;
using qtc_net_client_2.ClientModel;
using qtc_net_client_2.Properties;
using qtc_net_client_2.Services;
using QtCNETAPI.Dtos.User;
using QtCNETAPI.Models;
using QtCNETAPI.Schema;
using QtCNETAPI.Services.ApiService;
using QtCNETAPI.Services.GatewayService;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using QtCNETAPI.Services.GatewayService;
using qtc_net_client_2.ClientModel;
using qtc_net_client_2.Properties;
using qtc_net_client_2.Services;
using QtCNETAPI.Schema;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
namespace qtc_net_client_2.Forms
{
public partial class Profile : Form
{
private UserInformationDto _userInformationDto;
private ImageFactory _imgFactory = new();
private IApiService _apiService;
private IGatewayService _gatewayService;
private ServiceResponse<byte[]>? pfpRes;
byte[]? cosmeticRes;
private List<Contact> contactsList;
public Profile(UserInformationDto userInfo, ServiceResponse<byte[]>? pfp, List<Contact> contacts, IApiService apiService, IGatewayService gatewayService)
public Profile(UserInformationDto userInfo, ServiceResponse<byte[]>? pfp, List<Contact> contacts, IApiService apiService, IGatewayService gatewayService, byte[]? cosmetic = null)
{
_userInformationDto = userInfo;
_apiService = apiService;
_gatewayService = gatewayService;
pfpRes = pfp;
cosmeticRes = cosmetic;
contactsList = contacts;
InitializeComponent();
@ -47,53 +52,45 @@ namespace qtc_net_client_2.Forms
lblCurrencyAmount.Text = _userInformationDto.CurrencyAmount.ToString("N0");
rtxtBio.Text = _userInformationDto.Bio;
pbUserPfp.Location = new(13, 11);
pbUserPfp.Size = new(128, 128);
Bitmap? pfp = null;
if (pfpRes != null && pfpRes.Success && pfpRes.Data != null)
{
using (var ms = new MemoryStream(pfpRes.Data))
{
pbUserPfp.Image = new Bitmap(ms);
pfp = new Bitmap(ms);
}
}
var userStatus = (UserStatus)_userInformationDto.Status;
Bitmap precenseImage = Resources.OnlineIcon;
switch (userStatus)
{
case UserStatus.Online:
pbUserStatus.Image = Resources.OnlineIcon;
precenseImage = Resources.OnlineIcon;
break;
case UserStatus.Away:
pbUserStatus.Image = Resources.AwayIcon;
precenseImage = Resources.AwayIcon;
break;
case UserStatus.DoNotDisturb:
pbUserStatus.Image = Resources.DNDIcon;
precenseImage = Resources.DNDIcon;
break;
case UserStatus.Offline:
pbUserStatus.Image = Resources.OfflineIcon;
precenseImage = Resources.OfflineIcon;
break;
}
if (_userInformationDto.ProfileCosmeticId != 0)
Bitmap? cosmetic = null;
if(cosmeticRes != null)
{
var res = await _apiService.GetStoreItem(_userInformationDto.ProfileCosmeticId);
if (res != null && res.Success && res.Data != null)
{
var client = new HttpClient();
var response = await client.GetAsync(res.Data.AssetUrl);
if (response.IsSuccessStatusCode)
{
using (var stream = await response.Content.ReadAsStreamAsync())
{
CombineProfileImageWithCosmetic(pbUserPfp.Image, new Bitmap(stream));
}
response.Dispose();
}
client.Dispose();
}
using var ms = new MemoryStream(cosmeticRes);
cosmetic = new Bitmap(ms);
}
pbUserPfp.Image = _imgFactory.CreateProfileImage(precenseImage, pfp, cosmetic);
precenseImage.Dispose();
pfp?.Dispose();
cosmetic?.Dispose();
if (_userInformationDto.Id == _apiService.CurrentUser!.Id)
{
btnAddContact.Visible = false;
@ -185,6 +182,9 @@ namespace qtc_net_client_2.Forms
private async void btnAddContact_Click_Remove(object sender, EventArgs e)
{
var msgBoxResult = MessageBox.Show("Are You Sure You Want To Remove This User From Your Contacts?", "Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (msgBoxResult == DialogResult.No) return;
var result = await _apiService.RemoveContactFromCurrentUser(_userInformationDto.Id);
if (result.Success)
{
@ -211,6 +211,9 @@ namespace qtc_net_client_2.Forms
private async void btnDecline_Click(object sender, EventArgs e)
{
var msgBoxResult = MessageBox.Show("Are You Sure You Want To Decline This Request?", "Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (msgBoxResult == DialogResult.No) return;
var result = await _apiService.RemoveContactFromCurrentUser(_userInformationDto.Id);
if (result.Success)
{
@ -225,6 +228,9 @@ namespace qtc_net_client_2.Forms
private async void btnCancelRequest_Click(object sender, EventArgs e)
{
var msgBoxResult = MessageBox.Show("Are You Sure You Want To Cancel This Request?", "Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (msgBoxResult == DialogResult.No) return;
var result = await _apiService.RemoveContactFromCurrentUser(_userInformationDto.Id);
if (result.Success)
{
@ -242,24 +248,5 @@ namespace qtc_net_client_2.Forms
Close();
frmDirectMessage.Show();
}
private void CombineProfileImageWithCosmetic(Image pfp, Bitmap cosmetic)
{
cosmetic.MakeTransparent();
Bitmap combined = new Bitmap(139, 138);
using (Graphics g = Graphics.FromImage(combined))
{
g.Clear(Color.Transparent);
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
g.DrawImage(pfp, 4, 6, 128, 128);
g.DrawImage(cosmetic, 0, 0, 139, 138);
}
pbUserPfp.Location = new(9, 5);
pbUserPfp.Size = new(139, 138);
pbUserPfp.Image = combined;
}
}
}

View File

@ -17,6 +17,7 @@ namespace qtc_net_client_2.Forms
public partial class ProfileEdit : Form
{
IApiService _apiService;
private int currentCosmetic = 0;
public ProfileEdit(IApiService apiService)
{
_apiService = apiService;
@ -65,11 +66,13 @@ namespace qtc_net_client_2.Forms
cbCosmetic.DataSource = items;
cbCosmetic.SelectedIndex = cbCosmetic.Items.IndexOf(items.FirstOrDefault(e => (int?)e.Value == _apiService.CurrentUser.ActiveProfileCosmetic));
currentCosmetic = cbCosmetic.Items.IndexOf(items.FirstOrDefault(e => (int?)e.Value == _apiService.CurrentUser.ActiveProfileCosmetic));
}
private async void btnSave_Click(object sender, EventArgs e)
{
ComboBoxItem? selectedItem = (ComboBoxItem?)cbCosmetic.SelectedItem;
int selectedItemId = 0;
// update user info
UserUpdateInformationDto userUpdateInformationDto = new UserUpdateInformationDto
@ -82,7 +85,7 @@ namespace qtc_net_client_2.Forms
if (selectedItem != null)
{
int selectedItemId = (int?)selectedItem.Value ?? 0;
selectedItemId = (int?)selectedItem.Value ?? 0;
userUpdateInformationDto.ProfileCosmeticId = selectedItemId;
}
@ -90,7 +93,8 @@ namespace qtc_net_client_2.Forms
if (res.Success)
{
DialogResult = DialogResult.OK;
if (currentCosmetic != selectedItemId) DialogResult = DialogResult.Yes; // trigger ui refresh
else DialogResult = DialogResult.OK;
Close();
}
else

View File

@ -43,6 +43,7 @@ namespace qtc_net_client_2.Forms
if(registerResult.Success)
{
MessageBox.Show("Registration Complete. If the server has email verification on, you may need to check your email for a verification link.\nIf you do not receive one, try logging in.");
DialogResult = DialogResult.OK;
Close();
} else

View File

@ -0,0 +1,104 @@
namespace qtc_net_client_2.Forms
{
partial class ResendVerificationEmail
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
pbLoginBanner = new PictureBox();
tbEmail = new TextBox();
lblHeader = new Label();
btnSend = new Button();
((System.ComponentModel.ISupportInitialize)pbLoginBanner).BeginInit();
SuspendLayout();
//
// pbLoginBanner
//
pbLoginBanner.Image = Properties.Resources.LoginBanner;
pbLoginBanner.Location = new Point(-4, 0);
pbLoginBanner.Name = "pbLoginBanner";
pbLoginBanner.Size = new Size(521, 99);
pbLoginBanner.SizeMode = PictureBoxSizeMode.StretchImage;
pbLoginBanner.TabIndex = 1;
pbLoginBanner.TabStop = false;
//
// tbEmail
//
tbEmail.Location = new Point(50, 124);
tbEmail.Name = "tbEmail";
tbEmail.Size = new Size(424, 23);
tbEmail.TabIndex = 3;
//
// lblHeader
//
lblHeader.AutoSize = true;
lblHeader.Font = new Font("Segoe UI Light", 9F);
lblHeader.ForeColor = SystemColors.ControlLight;
lblHeader.Location = new Point(54, 106);
lblHeader.Name = "lblHeader";
lblHeader.Size = new Size(412, 15);
lblHeader.TabIndex = 5;
lblHeader.Text = "Please Enter Your Email, If An Account Exists With This Email, We'll Send You A Link";
//
// btnSend
//
btnSend.Location = new Point(224, 153);
btnSend.Name = "btnSend";
btnSend.Size = new Size(75, 23);
btnSend.TabIndex = 6;
btnSend.Text = "Send";
btnSend.UseVisualStyleBackColor = true;
btnSend.Click += btnSend_Click;
//
// ResendVerificationEmail
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
BackColor = Color.DodgerBlue;
ClientSize = new Size(515, 187);
Controls.Add(btnSend);
Controls.Add(lblHeader);
Controls.Add(tbEmail);
Controls.Add(pbLoginBanner);
FormBorderStyle = FormBorderStyle.FixedDialog;
MaximizeBox = false;
MinimizeBox = false;
Name = "ResendVerificationEmail";
StartPosition = FormStartPosition.CenterScreen;
Text = "QtC.NET Client - Resend Verification Email";
((System.ComponentModel.ISupportInitialize)pbLoginBanner).EndInit();
ResumeLayout(false);
PerformLayout();
}
#endregion
private PictureBox pbLoginBanner;
private TextBox tbEmail;
private Label lblHeader;
private Button btnSend;
}
}

View File

@ -0,0 +1,43 @@
using QtCNETAPI.Services.ApiService;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace qtc_net_client_2.Forms
{
public partial class ResendVerificationEmail : Form
{
private IApiService _apiService;
public ResendVerificationEmail(IApiService apiService)
{
_apiService = apiService;
InitializeComponent();
}
private async void btnSend_Click(object sender, EventArgs e)
{
if(!string.IsNullOrEmpty(tbEmail.Text))
{
tbEmail.Enabled = false;
btnSend.Enabled = false;
var result = await _apiService.ResendVerificationEmail(tbEmail.Text);
if(result != null && result.Success && result.Data)
{
MessageBox.Show("Got It! You should receive an email shortly.\nIf you do not receive an email, check your spam.", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
Close();
} else
{
MessageBox.Show("Sorry, This Server Doesn't Have Email Features Enabled Or Something Went Wrong.\nIf you cannot login, you may need to contact the server admin.", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
Close();
}
}
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,221 @@
namespace qtc_net_client_2.Forms
{
partial class ResetPassword
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
pEmailBox = new Panel();
btnSend = new Button();
lblHeader = new Label();
tbEmail = new TextBox();
pResetPasswordBox = new Panel();
btnResetPassword = new Button();
tbConfirmPassword = new TextBox();
lblConfirmPassword = new Label();
tbNewPassword = new TextBox();
lblNewPassword = new Label();
tbToken = new TextBox();
lblToken = new Label();
pbLoginBanner = new PictureBox();
pEmailBox.SuspendLayout();
pResetPasswordBox.SuspendLayout();
((System.ComponentModel.ISupportInitialize)pbLoginBanner).BeginInit();
SuspendLayout();
//
// pEmailBox
//
pEmailBox.Anchor = AnchorStyles.Bottom;
pEmailBox.BorderStyle = BorderStyle.FixedSingle;
pEmailBox.Controls.Add(btnSend);
pEmailBox.Controls.Add(lblHeader);
pEmailBox.Controls.Add(tbEmail);
pEmailBox.Location = new Point(101, 125);
pEmailBox.Name = "pEmailBox";
pEmailBox.Size = new Size(458, 94);
pEmailBox.TabIndex = 0;
//
// btnSend
//
btnSend.Location = new Point(193, 59);
btnSend.Name = "btnSend";
btnSend.Size = new Size(75, 23);
btnSend.TabIndex = 9;
btnSend.Text = "Send";
btnSend.UseVisualStyleBackColor = true;
btnSend.Click += btnSend_Click;
//
// lblHeader
//
lblHeader.AutoSize = true;
lblHeader.Font = new Font("Segoe UI Light", 9F);
lblHeader.ForeColor = SystemColors.ControlLight;
lblHeader.Location = new Point(23, 12);
lblHeader.Name = "lblHeader";
lblHeader.Size = new Size(412, 15);
lblHeader.TabIndex = 8;
lblHeader.Text = "Please Enter Your Email, If An Account Exists With This Email, We'll Send You A Link";
//
// tbEmail
//
tbEmail.Location = new Point(19, 30);
tbEmail.Name = "tbEmail";
tbEmail.Size = new Size(424, 23);
tbEmail.TabIndex = 7;
//
// pResetPasswordBox
//
pResetPasswordBox.Anchor = AnchorStyles.Bottom;
pResetPasswordBox.BorderStyle = BorderStyle.FixedSingle;
pResetPasswordBox.Controls.Add(btnResetPassword);
pResetPasswordBox.Controls.Add(tbConfirmPassword);
pResetPasswordBox.Controls.Add(lblConfirmPassword);
pResetPasswordBox.Controls.Add(tbNewPassword);
pResetPasswordBox.Controls.Add(lblNewPassword);
pResetPasswordBox.Controls.Add(tbToken);
pResetPasswordBox.Controls.Add(lblToken);
pResetPasswordBox.Location = new Point(17, 106);
pResetPasswordBox.Name = "pResetPasswordBox";
pResetPasswordBox.Size = new Size(596, 138);
pResetPasswordBox.TabIndex = 1;
pResetPasswordBox.Visible = false;
//
// btnResetPassword
//
btnResetPassword.Location = new Point(270, 102);
btnResetPassword.Name = "btnResetPassword";
btnResetPassword.Size = new Size(100, 23);
btnResetPassword.TabIndex = 15;
btnResetPassword.Text = "Reset Password";
btnResetPassword.UseVisualStyleBackColor = true;
btnResetPassword.Click += btnResetPassword_Click;
//
// tbConfirmPassword
//
tbConfirmPassword.Location = new Point(123, 73);
tbConfirmPassword.Name = "tbConfirmPassword";
tbConfirmPassword.PasswordChar = '*';
tbConfirmPassword.Size = new Size(424, 23);
tbConfirmPassword.TabIndex = 14;
//
// lblConfirmPassword
//
lblConfirmPassword.AutoSize = true;
lblConfirmPassword.Font = new Font("Segoe UI Light", 9F);
lblConfirmPassword.ForeColor = SystemColors.ControlLight;
lblConfirmPassword.Location = new Point(20, 76);
lblConfirmPassword.Name = "lblConfirmPassword";
lblConfirmPassword.Size = new Size(97, 15);
lblConfirmPassword.TabIndex = 13;
lblConfirmPassword.Text = "Confirm Password";
//
// tbNewPassword
//
tbNewPassword.Location = new Point(123, 44);
tbNewPassword.Name = "tbNewPassword";
tbNewPassword.PasswordChar = '*';
tbNewPassword.Size = new Size(424, 23);
tbNewPassword.TabIndex = 12;
//
// lblNewPassword
//
lblNewPassword.AutoSize = true;
lblNewPassword.Font = new Font("Segoe UI Light", 9F);
lblNewPassword.ForeColor = SystemColors.ControlLight;
lblNewPassword.Location = new Point(36, 47);
lblNewPassword.Name = "lblNewPassword";
lblNewPassword.Size = new Size(81, 15);
lblNewPassword.TabIndex = 11;
lblNewPassword.Text = "New Password";
//
// tbToken
//
tbToken.Location = new Point(123, 15);
tbToken.Name = "tbToken";
tbToken.Size = new Size(424, 23);
tbToken.TabIndex = 10;
//
// lblToken
//
lblToken.AutoSize = true;
lblToken.Font = new Font("Segoe UI Light", 9F);
lblToken.ForeColor = SystemColors.ControlLight;
lblToken.Location = new Point(82, 18);
lblToken.Name = "lblToken";
lblToken.Size = new Size(35, 15);
lblToken.TabIndex = 9;
lblToken.Text = "Token";
//
// pbLoginBanner
//
pbLoginBanner.Image = Properties.Resources.LoginBanner;
pbLoginBanner.Location = new Point(-3, -1);
pbLoginBanner.Name = "pbLoginBanner";
pbLoginBanner.Size = new Size(521, 99);
pbLoginBanner.SizeMode = PictureBoxSizeMode.StretchImage;
pbLoginBanner.TabIndex = 2;
pbLoginBanner.TabStop = false;
//
// ResetPassword
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
BackColor = Color.DodgerBlue;
ClientSize = new Size(622, 256);
Controls.Add(pEmailBox);
Controls.Add(pResetPasswordBox);
Controls.Add(pbLoginBanner);
FormBorderStyle = FormBorderStyle.FixedDialog;
MaximizeBox = false;
MinimizeBox = false;
Name = "ResetPassword";
StartPosition = FormStartPosition.CenterScreen;
Text = "QtC.NET Client - Reset Password";
pEmailBox.ResumeLayout(false);
pEmailBox.PerformLayout();
pResetPasswordBox.ResumeLayout(false);
pResetPasswordBox.PerformLayout();
((System.ComponentModel.ISupportInitialize)pbLoginBanner).EndInit();
ResumeLayout(false);
}
#endregion
private Panel pEmailBox;
private Button btnSend;
private Label lblHeader;
private TextBox tbEmail;
private Panel pResetPasswordBox;
private TextBox tbConfirmPassword;
private Label lblConfirmPassword;
private TextBox tbNewPassword;
private Label lblNewPassword;
private TextBox tbToken;
private Label lblToken;
private Button btnResetPassword;
private PictureBox pbLoginBanner;
}
}

View File

@ -0,0 +1,68 @@
using QtCNETAPI.Services.ApiService;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace qtc_net_client_2.Forms
{
public partial class ResetPassword : Form
{
private IApiService _apiService;
public ResetPassword(IApiService apiService)
{
_apiService = apiService;
InitializeComponent();
}
private async void btnSend_Click(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(tbEmail.Text))
{
tbEmail.Enabled = false;
btnSend.Enabled = false;
var result = await _apiService.SendPasswordResetEmail(tbEmail.Text);
if (result != null && result.Success && result.Data)
{
pEmailBox.Visible = false;
pResetPasswordBox.Visible = true;
MessageBox.Show("Got It! You should receive an email shortly.\nIf you do not receive an email, check your spam.");
}
else
{
MessageBox.Show("Sorry, This Server Doesn't Have Email Features Enabled Or Something Went Wrong.\nIf you cannot login, you may need to contact the server admin.", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
Close();
}
}
}
private async void btnResetPassword_Click(object sender, EventArgs e)
{
if(!string.IsNullOrEmpty(tbToken.Text) && !string.IsNullOrEmpty(tbNewPassword.Text) && !string.IsNullOrEmpty(tbConfirmPassword.Text))
{
tbToken.Enabled = false;
tbNewPassword.Enabled = false;
tbConfirmPassword.Enabled = false;
btnResetPassword.Enabled = false;
var result = await _apiService.ResetPassword(new QtCNETAPI.Dtos.User.UserPasswordResetDto { Token = tbToken.Text, Password = tbNewPassword.Text });
if(result != null && result.Success && result.Data)
{
MessageBox.Show("Your Password Has Been Reset. You may now login with the new password.", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
Close();
} else
{
MessageBox.Show(result?.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
Close();
}
}
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -87,10 +87,12 @@ namespace qtc_net_client_2.Forms
};
await _apiService.UpdateUserInformationAsync(updateDto);
DialogResult = DialogResult.Yes;
}
}
else MessageBox.Show("We Weren't Able To Complete Your Purchase.\nYou May Not Have Enough Funds For This Item.", "Oops.", MessageBoxButtons.OK, MessageBoxIcon.Error);
DialogResult = DialogResult.OK;
Close();
}
}

View File

@ -19,7 +19,7 @@ namespace qtc_net_client_2.Properties {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
@ -81,7 +81,7 @@ namespace qtc_net_client_2.Properties {
}
/// <summary>
/// Looks up a localized string similar to 6.2.1.
/// Looks up a localized string similar to 6.5.5.
/// </summary>
internal static string AssemblyVersion {
get {
@ -269,6 +269,16 @@ namespace qtc_net_client_2.Properties {
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap RoomsChatIcon {
get {
object obj = ResourceManager.GetObject("RoomsChatIcon", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>

View File

@ -173,7 +173,7 @@
<value>..\Icons\MessageIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="AssemblyVersion" xml:space="preserve">
<value>6.2.1</value>
<value>6.5.5</value>
</data>
<data name="cobalt_sittingatputer" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\cobalt_sittingatputer.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
@ -193,4 +193,7 @@
<data name="DefaultPfp" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\DefaultPfp.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="RoomsChatIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Icons\RoomsChatIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

View File

@ -0,0 +1,40 @@
using qtc_net_client_2.Properties;
using System;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace qtc_net_client_2.Services
{
public class ImageFactory
{
public Bitmap CreateProfileImage(Bitmap? precenseImage = null, Bitmap? pfp = null, Bitmap? cosmetic = null)
{
Bitmap combined = new Bitmap(139, 138);
using Graphics g = Graphics.FromImage(combined);
g.Clear(Color.Transparent);
g.CompositingMode = CompositingMode.SourceOver;
pfp ??= Resources.DefaultPfp;
g.DrawImage(pfp, 4, 6, 128, 128);
if (cosmetic != null)
{
cosmetic.MakeTransparent();
g.DrawImage(cosmetic, 0, 0, 139, 138);
}
if(precenseImage != null)
{
precenseImage.MakeTransparent();
g.DrawImage(precenseImage, 104, 0, 35, 35);
}
return combined;
}
}
}